ErrLookup › Background articles › Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError)
Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError)
"Request timed out" errors appear when a client library enforces its own time budget on an HTTP or RPC request and aborts it before a response arrives — you'll meet them as APITimeoutError in LiteLLM, TIMED_OUT in Actual Budget, REQUEST_TIMEOUT in the Mastra CLI, TransportError::Timeout in Codex, or any "timed out after Nms" message. This article explains where these timeouts come from, why the abort is client-side and often ambiguous, and how to size budgets, distinguish caller cancellation from real timeouts, and retry safely.
Distilled from 95 documented records across 39 repositories.
Background
This family is produced by the client, not the server. Every record here describes the same mechanism: a library wraps an outbound request in a deadline — a tokio::time::timeout, an AbortController with setTimeout, a future.get(deadlineMillis), or an HTTP client's connect/read timeout — and when the round trip (or one of its phases) exceeds that budget, the in-flight request is cancelled locally and rethrown as a typed error. The server may still be processing, or may never have received the request; the caller gets no response either way. That is why the error is inherently ambiguous: CodeWhale's MCP and OpenCLI's MiniMax records both warn that an aborted request may have succeeded server-side (and, for billable APIs, may have been charged), while oh-my-pi explicitly marks notification timeouts non-retryable because a replay could double-apply side effects.
What the deadline actually covers varies sharply by library. Some budgets are whole-operation: openai/codex's RouteAwareRequestBuilder::timeout starts before proxy/PAC route resolution and spans connect, TLS, send, body transfer, and every redirect hop, recomputing remaining time per hop; apache/hadoop's ABFS tail-latency guard bounds the entire REST call and deliberately discards the connection when it fires; deno's OTLP gRPC export wraps connect plus response plus body in one OTEL_EXPORTER_OTLP_TIMEOUT window. Others bound a single phase, such as CodeWhale's per-frame read timeout or Codex's connect-only option. And some budgets are fixed constants you cannot configure — santifer/career-ops hardcodes a 15s MODEL_TIMEOUT_MS, and cjpais/Handy uses a fixed 60s stall timeout — while others are per-call parameters, environment variables (OPENAI_TIMEOUT_MS, OTEL_EXPORTER_OTLP_TIMEOUT), or user settings (SiYuan's RequestTimeout, CodeWhale's mcp.json timeouts.read_timeout).
From the caller's side the same mechanism wears many masks. LiteLLM string-matches several timeout phrases from provider SDKs and normalizes them to litellm.Timeout, and maps Bedrock connect/read failures to a uniform 408; mastra-ai/mastra converts a raw AbortError into a typed ApiCliError('REQUEST_TIMEOUT'); actualbudget/actual wraps any SimpleFin sync failure — including the timeout — as BankSyncError('TIMED_OUT'). Two pitfalls recur across records: cancellation conflation and id-loss. In tinyhumansai/openhuman's cloud and LAN transports, the caller's own abort signal is wired to the same AbortController as the timer, so a deliberate cancellation is reported with a "timed out" message; the Anthropic client in oh-my-pi does the opposite and carefully distinguishes its internal timeout from a caller abort. In CodeWhale's LSP and MCP clients, responses that arrive with a missing or wrong request id are silently skipped, guaranteeing a timeout that looks like slowness but is a protocol bug.
Triggers cluster into a few groups across all 39 repositories: genuinely slow work (large generations, video embeddings, big prompt bundles, huge directory listings), cold paths (first LSP request after spawn, npx servers downloading dependencies during a 30s handshake, self-hosted model cold starts), network degradation between client and server (Wi-Fi latency, proxies, VPNs, congested egress, throttling 429/503 bursts on ABFS), and budgets simply set below the operation's real latency. Most records agree the failure is transient by design and retrying with a fresh deadline is the right default — with the caveat that retries need backoff, a new deadline (codex warns never to reuse an elapsed one), and an idempotency check when the request has side effects.
Common causes
- Budget smaller than real operation latency. The request legitimately needs more time than the configured timeout: large prompts and long model generations against a fixed 15s window, video embeddings against a 300s default, or full-history bank syncs against 60-300s limits. Defaults are frequently too tight for heavy endpoints — openhuman's LAN default is only 10s.
- Network path degradation. Wi-Fi latency, congested egress, VPN/proxy stalls, DNS slowness, or packet loss push the round trip past the deadline. Several records (career-ops, agentmemory, CodeWhale's doctor probe) note that when many targets time out at once, the network — not the provider — is usually at fault.
- Server-side slowness or hang. A hung or deadlocked server, GC pause, blocked event loop, cold-starting model, or an overloaded collector/backend never answers in time. Persistent timeouts on one endpoint usually mean the server is slow or stuck, not that the budget is small.
- Cold-start and first-use paths. First request after spawn charges warm-up work against the budget: an LSP server still indexing a large workspace, an npx-based MCP server downloading dependencies during the 30s handshake, a self-hosted model cold start, or core migrations on app boot.
- Upstream/aggregator timeouts surfaced as your client's timeout. Intermediaries abandon the request server-side: Enable Banking returns HTTP 408 when the upstream bank is slow, SimpleFin times out aggregating from banks, and LiteLLM's string-matching relabels provider-SDK timeout exceptions into one uniform error.
- Cancellation misreported as timeout. In openhuman's cloud and LAN transports the caller's abort signal shares an AbortController with the timeout timer, so deliberate cancellation surfaces as "timed out after Nms". Check your own signal's aborted state before classifying; oh-my-pi's Anthropic client shows the contrasting pattern of keeping them separate.
- Protocol bugs that guarantee a timeout. CodeWhale's MCP/LSP clients skip any response whose JSON-RPC id doesn't match the pending request, so a server echoing wrong or missing ids always times out no matter how fast it replies. Throttling bursts (429/503 on ABFS) similarly stall requests past their tail-latency deadline.
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Go deeper
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Documented occurrences
- Request Duration Exceeded Tail Latency Threshold. (apache/hadoop)
- [transport:cloud] ${method} timed out after ${this.timeoutMs}ms (tinyhumansai/openhuman)
- route-aware request timed out (openai/codex)
- MCP server '{server}': {method} timed out after {timeout:?} (Hmbown/CodeWhale)
- Timeout after ${MODEL_TIMEOUT_MS / 1000}s (santifer/career-ops)
- Core RPC ${payload.method} timed out after ${effectiveTimeoutMs}ms (tinyhumansai/openhuman)
- LSP request timed out for {method} (Hmbown/CodeWhale)
- [transport:lan] ${method} timed out after ${this.timeoutMs}ms (tinyhumansai/openhuman)
- Pinned model timed out after ${MODEL_TIMEOUT_MS / 1000}s (santifer/career-ops)
- APITimeoutError - Request timed out. Error_str: {error_str} (BerriAI/litellm)
- OpenAI API request timed out after ${this.timeoutMs}ms — set OPENAI_TIMEOUT_MS (or AGENTMEMORY_LLM_TIMEOUT_MS) to raise the bound or check the provider status. (rohitg00/agentmemory)
- timeout (openai/codex)
- Timeout error occurred. (BerriAI/litellm)
- OTEL export timed out after {}ms (denoland/deno)
- timeout: Request timeout from Enable Banking API (we-promise/sure)
- AI editor request timeout (siyuan-note/siyuan)
- Notify timeout after ${timeout}ms (can1357/oh-my-pi)
- Timeout error occurred. (BerriAI/litellm)
- no response within {}s from {} (cjpais/Handy)
- MiniMax music generation (jackwener/OpenCLI)
…and 75 more across the corpus — use search.
Honest provenance: generated on 2026-08-31 from AI-assisted analysis of the linked records. See how records are made.