System.Net.Http.HttpRequestException

An HttpRequestException is thrown by HttpClient when a request fails. It can mean that the server could not be reached, that the name could not be resolved, that a certificate was not trusted, or, when you call EnsureSuccessStatusCode, that the server answered with an error status.

The message and the inner exception tell which one it is. From .NET 5, the StatusCode and HttpRequestError properties tell you without parsing the message.

Minimum version: >= 4.5 >= Core 1.0

Statistics

19
elmah.io logo 11

Common causes

The request did not give a successful response. The first thing to find out is whether the server ever answered.

The server cannot be reached

The connection was refused or the address does not exist, because the service is down, the port is wrong, or a firewall blocks the call. The inner exception is a SocketException that has the details.

using var client = new HttpClient();
var json = await client.GetStringAsync("http://localhost:1/prices");   // HttpRequestException: connection refused

Check the address, the port and that the service is running. Handle the failure, if the service can be down:

using var client = new HttpClient();

try
{
    var json = await client.GetStringAsync("http://localhost:1/prices");
}
catch (HttpRequestException e) when (e.HttpRequestError == HttpRequestError.ConnectionError)
{
    logger.LogWarning(e, "The price service is not available");
}

Methods such as GetStringAsync and EnsureSuccessStatusCode throw when the status is not in the 200 range. The StatusCode property has the number.

using var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/prices");
response.EnsureSuccessStatusCode();   // HttpRequestException: Response status code does not indicate success: 404 (Not Found)

Read the status, and decide what each one means for your code. Use the status instead of an exception when an error is expected:

using var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/prices");

if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
    Console.WriteLine("No prices yet.");
}
else
{
    response.EnsureSuccessStatusCode();
}

A host name that cannot be resolved gives No such host is known, and a certificate that is expired or does not match the name gives The SSL connection could not be established. A proxy or firewall in the way can cause both.

Check the name from the machine that runs the code, with nslookup and curl. For certificates, fix the certificate. Do not turn off the validation in code.

How to fix it and prevent it

Use IHttpClientFactory

Create clients through IHttpClientFactory or a typed client. It reuses connections and refreshes DNS, which avoids a long list of connection problems.

builder.Services.AddHttpClient<PriceClient>(client =>
{
    client.BaseAddress = new Uri("https://api.example.com");
});

Remote calls fail. Decide what your code does when it does: retry, use a cached value, or tell the user. The resilience handler adds retries with a delay, a timeout and a circuit breaker.

builder.Services.AddHttpClient("prices").AddStandardResilienceHandler();

The message does not always include the address. Catch the exception where the URL is known, and log the host, the status code and the HttpRequestError, but not any secrets in the query string.

How to read the stack trace

The outer exception has the message, and the inner exception is the cause. Look at the inner exception first:

System.Net.Http.HttpRequestException: No connection could be made because the target machine actively refused it. (localhost:5001)
 ---> System.Net.Sockets.SocketException (10061): No connection could be made because the target machine actively refused it.
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.InjectNewHttp11ConnectionAsync(QueueItem queueItem)
   at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.SocketsHttpHandler.<SendAsync>g__CreateHandlerAndSendAsync|115_0(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.GetStringAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at Shop.Services.PriceClient.GetPrices(String url) in C:\src\Shop\Services\PriceClient.cs:line 12
   at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 5

The inner exception is a SocketException with the code 10061, so the server was reached but nothing was listening on the port (localhost:5001). The call that started it, line 12 of PriceClient.cs, is at the bottom of the trace. If the inner exception is missing, check the StatusCode property.

Should you catch it?

Yes. Remote calls fail for reasons you cannot control, so catching HttpRequestException around them is normal. Filter on StatusCode or HttpRequestError to handle the cases you know.

Do not retry on every error. A 400 or a 404 will fail again, and a connection error or a 503 may work the next time.

Find HttpRequestException before your users do

elmah.io logs every unhandled exception in your .NET application with its stack trace and request details, groups identical errors and notifies you when a new one appears.

Start free trial
Free 21-day trial No credit card required

Related exceptions

Frequently asked questions

How do I get the status code from HttpRequestException?

Use e.StatusCode. It is set when the exception comes from EnsureSuccessStatusCode or GetStringAsync, and null when the request did not get a response.

It is the generic message when the request could not be sent. Read the inner exception. It tells whether the cause is the connection, the name, the certificate or something else.

No. Setting a handler that accepts every certificate removes the protection of HTTPS. Install the right certificate, or trust the one authority on the machine for development.

Yes. A single instance or one from IHttpClientFactory is meant to be used for many requests. Creating a client for each request can exhaust the sockets of the machine.

Let your AI agent track it down

Connect Claude Code, Cursor, VS Code or Visual Studio to the elmah.io MCP server and ask your agent to look into HttpRequestException for you. For example:

AI chat
Find the most frequent HttpRequestException in my production log and show me the line that throws it.

The agent reads the stack trace and request details from elmah.io, finds the code in your repository and proposes a fix. In Claude Code, add the server with one command:

claude mcp add --transport http --client-id claudecode elmahio https://mcp.elmah.io/mcp

The MCP server is included on every plan and is currently in beta. Set up the MCP server.

Further reading

YouTube videos

Answers from Stack Overflow

You are doing it right with ServerCertificateValidationCallback. This is not the problem you are facing. The problem you are facing is most likely the version of SSL/TLS protocol.

For example, if your server offers only SSLv3 and TLSv10 and your client needs TLSv12 then you will receive this error message. What you need to do is to make sure that both client and server have a common protocol version supported.

When I need a client that is able to connect to as many servers as possible (rather than to be as secure as possible) I use this (together with setting the validation callback):

  ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

By Wapac. Read the original answer on Stack Overflow.

It's probably caused by a local network connectivity issue (but also a DNS error is possible). Unfortunately HResult is generic, however you can determine the exact issue catching HttpRequestException and then inspecting InnerException: if it's a WebException then you can check the WebException.Status property, for example WebExceptionStatus.NameResolutionFailure should indicate a DNS resolution problem.


It may happen, there isn't much you can do.

What I'd suggest to always wrap that (network related) code in a loop with a try/catch block (as also suggested here for other fallible operations). Handle known exceptions, wait a little (say 1000 msec) and try again (for say 3 times). Only if failed all times then you can quit/report an error to your users. Very raw example like this:

private const int NumberOfRetries = 3;
private const int DelayOnRetry = 1000;

public static async Task<HttpResponseMessage> GetFromUrlAsync(string url) {
    using (var client = new HttpClient()) {
        for (int i=1; i <= NumberOfRetries; ++i) {
            try {
                return await client.GetAsync(url); 
            }
            catch (Exception e) when (i < NumberOfRetries) {
                await Task.Delay(DelayOnRetry);
            }
        }
    }
}

By Adriano Repetti. Read the original answer on Stack Overflow.

As you are using HttpClient, try to use response.EnsureSuccessStatusCode();

Now HttpClient will throw exception when response status is not a success code.

try
{
    HttpResponseMessage response = await client.GetAsync("http://www.ajshdgasjhdgajdhgasjhdgasjdhgasjdhgas.tk/");
    response.EnsureSuccessStatusCode();    // Throw if not a success code.

    // ...
}
catch (HttpRequestException e)
{
    // Handle exception.
}

ORIGINAL SOURCE OF THE CODE: http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client

By mirushaki. Read the original answer on Stack Overflow.

You just need to keep digging. The exception "The response ended prematurely" isn't the root cause. Keep digging into the inner exceptions until you find the last one. You'll find this:

System.IO.IOException: Authentication failed because the remote party has closed the transport stream.

So it's not about your code. It seems the server you're hitting either can't handle the load, or is intentionally dropping your requests because you're hitting it too hard.

By Gabriel Luci. Read the original answer on Stack Overflow.

We have been solving the same problem just today, and all you need to do is to increase the runtime version of .NET

4.5.2 didn't work for us with the above problem, while 4.6.1 was OK

If you need to keep the .NET version, then set

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

By martinh_kentico. Read the original answer on Stack Overflow.