System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 2 seconds elapsing.
means the server did not answer within the client's Timeout, so HttpClient abandoned the
request. The server may be slow, stuck, or doing more work than the call deserves.
Find out why the endpoint takes that long, then give each call a budget that fits it with a
CancellationTokenSource, and let the server stop its work when the client gives up.
The error
Unhandled exception. System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 2 seconds elapsing.
---> System.TimeoutException: The operation was canceled.
---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
---> System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.
The client and the endpoint behind it:
using var client = new HttpClient
{
BaseAddress = new Uri("http://127.0.0.1:15810/"),
Timeout = TimeSpan.FromSeconds(2)
};
var order = await client.GetFromJsonAsync<Order>("api/slow");
app.MapGet("/api/slow", async () =>
{
await Task.Delay(5000);
return new Order(7, "David Chen", 18.00m);
});
Why it happens
HttpClient.Timeout applies to every request the instance sends; when it runs out, the client
cancels the request and throws TaskCanceledException with an inner
TimeoutException. The inner exception and the words "HttpClient.Timeout" in the message are
how you know it was the timeout. The SocketException 995 underneath is only the aborted read, not a
network fault.
A cancelled token looks different. With the default timeout and a CancellationTokenSource of
2 seconds passed to the call, the exception was
TaskCanceledException: The operation was canceled. with no TimeoutException
and no mention of HttpClient.Timeout. Same type, different cause: something in your code cancelled the
token.
The server does not notice either way unless it listens. The /api/slow endpoint above takes
no token, so it has no way to learn that the client left; the cancellable version below does.
The fix
Set a generous ceiling on the client and a budget per call, and catch only your own cancellation:
using var client = new HttpClient
{
BaseAddress = new Uri("http://127.0.0.1:15810/"),
Timeout = TimeSpan.FromSeconds(30)
};
foreach (var seconds in new[] { 10, 2 })
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(seconds));
try
{
var order = await client.GetFromJsonAsync<Order>("api/slow-cancellable", cts.Token);
Console.WriteLine($"{seconds} s budget: {order}");
}
catch (OperationCanceledException) when (cts.IsCancellationRequested)
{
Console.WriteLine($"{seconds} s budget: api/slow-cancellable did not answer in time");
}
}
On the server, accept the request's CancellationToken and pass it on:
app.MapGet("/api/slow-cancellable", async (CancellationToken ct) =>
{
app.Logger.LogInformation("slow-cancellable started");
try
{
await Task.Delay(5000, ct);
}
10 s budget: Order { Id = 7, Customer = David Chen, Total = 18.00 }
2 s budget: api/slow-cancellable did not answer in time
The 10-second call got its answer; the 2-second call ended with a readable line, and the server logged
slow-cancellable: client went away, work stopped. If the endpoint is meant to be fast, the
timeout is doing its job and the real fix is on the server: a slow query, a lock, a call to another
service without its own timeout.
How it was reproduced
An empty web project (dotnet new web) on 127.0.0.1:15810 with a 5-second
Task.Delay in two endpoints, one ignoring and one honouring the request token, and a console
client (dotnet new console, no packages). .NET SDK 10.0.403, runtime 10.0.14, Windows 11.
The record, the delays and the names are the test's own.
Frequently asked
- What is the default HttpClient timeout in .NET?
- 100 seconds. The Timeout property applies to every request sent by that HttpClient instance; for different budgets per call, keep it as a ceiling and pass a CancellationToken from a CancellationTokenSource with its own delay.
- How do I tell an HttpClient timeout from a cancelled token?
- A timeout has an inner TimeoutException and its message names HttpClient.Timeout. A cancelled token gives TaskCanceledException: The operation was canceled. with no TimeoutException inside.
- Does the ASP.NET Core endpoint stop when the client times out?
- Only if it uses the request's CancellationToken. An endpoint that ignores it keeps working after the client has gone; one that passes the token to its awaits stops when the client disconnects.
A timeout one layer down, in the database, is in SQL Server: Execution Timeout Expired. More decoded errors in the Fixes category.