Fix: TaskCanceledException from HttpClient in.NET 8

Published: May 26, 2026 · By Kumar Kunal

The Error

Random failures calling external APIs:

System.Threading.Tasks.TaskCanceledException: A task was canceled.
---> System.TimeoutException: The operation was canceled.

Quick Fix - 1 Minute

HttpClient default timeout is 100 seconds. It throws TaskCanceledException on timeout, not TimeoutException. Increase it or fix DI.

Wrong - Creates new HttpClient each time:

public async Task CallApi()
{
    using var client = new HttpClient(); // BAD - socket exhaustion
    await client.GetAsync("https://api.com");
}

Right - Use IHttpClientFactory:

// Program.cs
builder.Services.AddHttpClient("ApiClient", client =>
{
    client.Timeout = TimeSpan.FromSeconds(30);
});

// Service public class ApiService { private readonly IHttpClientFactory _factory; public ApiService(IHttpClientFactory factory) => _factory = factory;

public async Task CallApi()
{
    var client = _factory.CreateClient("ApiClient");
    await client.GetAsync("https://api.com");
}

}

Why This Happens

1. Real timeout: External API is slow > 100s

2. Socket exhaustion: new HttpClient() in a loop opens thousands of ports. OS kills it

3. CancellationToken: Request cancelled by user closing browser

Real-World Scenario: Distinguishing Timeout vs User Cancel

TaskCanceledException has 3 causes. Check ex.CancellationToken.IsCancellationRequested to know which:

public async Task<string> CallApiSafely(CancellationToken userToken)
{
    var client = _factory.CreateClient("ApiClient");
    var timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
    using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(userToken, timeoutToken);
    
    try 
    {
        var response = await client.GetAsync("https://api.com", linkedCts.Token);
        return await response.Content.ReadAsStringAsync();
    }
    catch (OperationCanceledException ex) when (userToken.IsCancellationRequested)
    {
        // User closed browser or hit cancel button
        _logger.LogInformation("Request cancelled by user");
        throw;
    }
    catch (OperationCanceledException ex) when (timeoutToken.IsCancellationRequested)
    {
        // Your 10s timeout hit - API is slow
        _logger.LogWarning("API timeout after 10s");
        throw new TimeoutException("External API timed out", ex);
    }
}

Why this works: HttpClient throws the same exception for timeout and user cancel. Linked tokens let you tell them apart so you can retry timeouts but not user cancels.

Related Fixes You Should Know

HttpClient timeouts usually mean you have these issues too:

FAQ

Q: Why does HttpClient throw TaskCanceledException instead of TimeoutException?

By design. HttpClient.Timeout uses an internal CancellationTokenSource. When it fires, it cancels the request. Same exception as user cancellation. Check the token to differentiate.

Q: What is the default HttpClient timeout in.NET 8?

100 seconds. Way too long for web APIs. Set it to 5-30 seconds based on your SLA. Use Polly to retry 3 times instead of waiting 100s once.

Best Practice for.NET 8

1. Always use AddHttpClient: Manages socket lifetime

2. Set explicit timeout: client.Timeout = TimeSpan.FromSeconds(10);

3. Use Polly: Add retry policy for transient failures

builder.Services.AddHttpClient("ApiClient")
   .AddTransientHttpErrorPolicy(p => 
        p.WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(2)));

Related Dev Fixes

Found this helpful?

Master C# with our complete course. Real apps, real skills, job-ready in 2 hours.

Share this fix: Twitter LinkedIn

Comments on Fix: TaskCanceledException from HttpClient in.NET 8 (0)

No comments yet. Be the first to share your thoughts!