ErrLookupBackground 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

What usually fixes it

Go deeper

Documented occurrences

…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.