πŸ”§ Error Fixes
Β· 1 min read

C#: HttpClient Timeout β€” How to Fix It


TaskCanceledException: A task was canceled from HttpClient usually means the request timed out (default 100 seconds).

Why this happens

HttpClient has a default Timeout of 100 seconds. When a request exceeds this limit, HttpClient cancels the internal CancellationToken, which surfaces as a TaskCanceledException rather than a more descriptive timeout error. This is confusing because the same exception type is thrown for both user-initiated cancellations and timeouts, making it hard to distinguish the two without extra handling.

Fix 1: Increase the timeout

var client = new HttpClient {
    Timeout = TimeSpan.FromMinutes(5)
};

Fix 2: Use per-request cancellation tokens

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var response = await client.GetAsync(url, cts.Token);

Fix 3: Distinguish timeout from cancellation

try {
    var response = await client.GetAsync(url, cancellationToken);
} catch (TaskCanceledException ex) when (!cancellationToken.IsCancellationRequested) {
    // This is a timeout, not a user cancellation
    Console.WriteLine("Request timed out");
} catch (TaskCanceledException) {
    // User cancelled the request
    Console.WriteLine("Request cancelled");
}

Fix 4: Use HttpClientFactory

Don’t create HttpClient instances manually in ASP.NET Core. Use IHttpClientFactory to manage lifetimes and configure timeouts per named client:

services.AddHttpClient("slow-api", client => {
    client.Timeout = TimeSpan.FromMinutes(5);
});

Alternative solutions

Add a retry policy with Polly to handle transient timeouts automatically instead of just increasing the timeout:

services.AddHttpClient("my-api")
    .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)));

Prevention

  • Always set an explicit Timeout on HttpClient rather than relying on the 100-second default β€” choose a value that matches the expected response time of the downstream service.
  • Use IHttpClientFactory from the start in ASP.NET Core projects to avoid socket exhaustion and make timeout configuration centralized.

Related: C# cheat sheet Β· C#: ObjectDisposedException fix Β· Connection Timeout fix