Timeout Expired – Complete Fix Guide

Timeout Expired – Complete Fix Guide

⏳ Timeout Expired System.Data.SqlClient.SqlException / TaskCanceledException / ...

Complete troubleshooting guide — understand and fix timeout errors in SQL Server, HttpClient, ASP.NET Core, Entity Framework, and all .NET applications.

What is "Timeout expired"?

"Timeout expired" is a generic error message that appears when an operation exceeds its allotted time limit. In .NET, it can manifest in several forms:

  • SqlException"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."
  • TaskCanceledException – when an async task is cancelled due to a timeout (e.g., HttpClient.Timeout).
  • OperationCanceledException – when a CancellationToken triggers after a timeout.
  • HttpRequestException – often wrapped around a timeout from HttpClient.
  • Kestrel/ASP.NET Core request timeout – the request took too long and the server aborted it.

⚠️ Typical Stack Traces

System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
-- or --
System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 30 seconds elapsing.

Timeout errors are runtime exceptions that indicate a performance or scalability problem. They are often caused by slow external dependencies, insufficient resources, or misconfigured timeouts.

🔍 Root Causes

Timeouts can stem from various parts of your application stack. Here are the most frequent culprits:

1️⃣ SQL query too slow Database

Large dataset, missing indexes, complex joins, or blocking locks cause the query to exceed the CommandTimeout.

2️⃣ Network latency / DB connection issues Infrastructure

Slow network, firewall, or overloaded database server can exceed ConnectionTimeout.

3️⃣ HttpClient.Timeout too short HTTP

External API calls taking longer than the configured HttpClient.Timeout.

4️⃣ ASP.NET Core request timeout Web

Kestrel / IIS request timeout or IAsyncResult timeouts on long‑running endpoints.

5️⃣ Deadlocks or blocking Concurrency

Two or more transactions waiting for each other, causing a timeout.

6️⃣ Resource starvation Thread pool

Thread pool exhaustion can cause operations to wait before they even start, leading to timeouts.

🛠️ Step‑by‑Step Fixes

Apply these strategies in order to resolve timeout issues:

1 Identify the timeout origin

Check the stack trace and error message. Is it from SQL, HTTP, or the framework? This directs your fix.

2 Increase the timeout value (temporarily)

As a short‑term workaround, raise the timeout to see if the operation completes. But don't rely on this long‑term.

3 Optimize the operation

For SQL: add indexes, rewrite queries, use paging. For HTTP: reduce payload, cache results, use asynchronous streaming.

4 Implement retry logic

Use Polly or built‑in retry policies in EF Core / HttpClient to handle transient failures.

5 Use cancellation tokens for async operations

Allow users to cancel long‑running operations and avoid hanging threads.

6 Monitor and log

Add logging to track which operations are timing out and their execution time to pinpoint bottlenecks.

✅ Quick Tip

For SQL timeouts, consider using SET LOCK_TIMEOUT to avoid indefinite waits, or implement WITH (NOLOCK) for read‑only queries (with caution).

🗄️ SQL Server and Entity Framework Core

In SQL Server, timeouts are governed by two connection‑string parameters: Connection Timeout (for establishing a connection) and CommandTimeout (for executing a command).

Connection Timeout

// Connection string with increased connection timeout "Server=myServer;Database=myDB;User Id=myUser;Password=myPass;Connection Timeout=60" // Default is 15 seconds.

Command Timeout (SQL Command / EF Core)

// For SqlCommand using (var cmd = new SqlCommand(query, connection)) { cmd.CommandTimeout = 120; // seconds // execute } // For EF Core optionsBuilder.UseSqlServer(connectionString, options => options.CommandTimeout(120));

EF Core – per operation

var result = await context.Orders .FromSqlRaw("SELECT * FROM Orders WHERE ...") .ToListAsync(); // Or set command timeout on the context (if using DbContext). ((IObjectContextAdapter)context).ObjectContext.CommandTimeout = 120;

⚠️ Warning

Increasing timeouts may mask performance issues. Always optimize queries first. Use SET STATISTICS TIME and execution plans to identify slow parts.

Handling deadlocks

Deadlocks often appear as timeouts. Use SET DEADLOCK_PRIORITY and implement retry logic with exponential backoff (using Polly).

🌐 HttpClient and API Calls

HttpClient has a Timeout property that defaults to 100 seconds. You can set it to a value that suits your external API.

// ❌ Default timeout may be too short for some endpoints var client = new HttpClient(); var response = await client.GetAsync("https://slow-api.example.com"); // ✅ Set a custom timeout client.Timeout = TimeSpan.FromMinutes(2); // Or use a CancellationToken with a timeout using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); var response = await client.GetAsync("https://...", cts.Token);

For retries, use Polly with HttpClientFactory (in ASP.NET Core) to automatically retry failed requests.

// In Program.cs builder.Services.AddHttpClient("MyClient") .ConfigureHttpClient(c => c.Timeout = TimeSpan.FromSeconds(60)) .AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))));

🌐 ASP.NET Core Request Timeouts

ASP.NET Core (Kestrel) has built‑in request timeout settings. If an endpoint takes longer than the configured limit, the request is aborted.

Configure Kestrel timeout

// In Program.cs builder.WebHost.ConfigureKestrel(options => { options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2); options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30); });

For long‑running operations, consider using the RequestTimeout middleware (available in .NET 8+).

// In Program.cs app.UseRequestTimeout(TimeSpan.FromSeconds(60));

Alternatively, you can use IAsyncResult or Task timeouts via CancellationToken passed from HttpContext.RequestAborted.

public async Task<IActionResult> LongRunning(CancellationToken cancellationToken) { var token = cancellationToken; // automatically triggered when client disconnects // ... }

Async Tasks and Cancellation

When you await a task, you can use Task.Wait or Task.WhenAny with a timeout to avoid indefinite blocking.

// ❌ Blocking wait – can cause timeout issues var result = await SomeAsyncMethod(); // no timeout // ✅ Use a timeout using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); var task = SomeAsyncMethod(cts.Token); await task; // Or use Task.WhenAny to implement fallback var completed = await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(30))); if (completed == task) { /* success */ } else { /* timeout */ }

Always pass cancellation tokens to async APIs to enable cooperative cancellation.

🔁 Retry and Circuit Breaker Patterns

Transient faults (like temporary network issues or overloaded services) can cause timeouts. Use Polly to implement resilience.

// Retry policy for SQL Policy .Handle<SqlException>(ex => ex.Number == 1205) // deadlock .Or<TimeoutException>() .WaitAndRetry(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); // Circuit breaker to avoid hammering a failing service Policy .Handle<Exception>() .CircuitBreaker(5, TimeSpan.FromSeconds(30));

In ASP.NET Core, integrate Polly with HttpClientFactory as shown earlier.

🧪 Testing Timeout Scenarios

When writing tests, you may want to simulate timeouts to verify your handling logic.

// Mock a slow API using a Task.Delay var mockHttp = new Mock<IHttpClient>(); mockHttp.Setup(x => x.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())) .Returns(async () => { await Task.Delay(5000); // simulate 5-second delay return new HttpResponseMessage(); });

Then test that your code handles the timeout gracefully (e.g., by catching TaskCanceledException).

🛡️ Prevention and Best Practices

✅ Use timeouts defensively

Set appropriate timeouts for all external dependencies (DB, HTTP, etc.) to avoid hanging resources.

✅ Optimize queries and indexes

Ensure your SQL queries are efficient and use covering indexes to reduce execution time.

✅ Use async/await with cancellation tokens

Always pass CancellationToken to async methods and use ThrowIfCancellationRequested to abort early.

✅ Implement retry and circuit breaker

Handle transient failures gracefully with Polly to improve resilience.

✅ Monitor performance

Use Application Insights, logging, or APM tools to track slow operations and timeouts in production.

✅ Consider asynchronous streaming

For large datasets, use streaming APIs (e.g., IAsyncEnumerable) to avoid loading everything at once.

🏆 Pro Tip

For SQL Server, use SET XACT_ABORT ON to ensure transactions are rolled back on timeout, preventing resource leaks. Also, consider using WITH (READUNCOMMITTED) for read‑only queries to avoid locking (if consistency is not critical).

Post a Comment

0 Comments