A timeout on an LLM call is a race between layers, and the tightest one wins. The OpenAI and Anthropic Python SDKs both default to 600 seconds total with a 5 second connect timeout. Cloudflare's Proxy Read Timeout is 125 seconds, an AWS ALB idles out at 60, nginx reads for 60, and Vercel and Cloud Run both stop at 300. So the SDK timeout is almost never the one that fires. Identify the layer from the failure shape: an SDK APITimeoutError is yours, a Cloudflare-branded 524 HTML page is the CDN, and an unbranded blank 504 is something else in the path. Streaming fixes most of it, because a proxy read timeout measures the gap between reads rather than the total duration.
- SDK defaults are 600 seconds total, 5 seconds connect, on both OpenAI and Anthropic Python clients.
- Cloudflare's 524 fires at 125 seconds, not the 100 that most articles still quote.
- An ALB idles out at 60 seconds and explicitly does not reset on HTTP/2 PING frames.
- Streaming resets the read clock. A proxy read timeout measures the gap between reads, not the total.
- Anthropic SDKs refuse a non-streaming request expected to exceed ten minutes, before sending it.
- A 504
timeout_errorfrom Anthropic is the server timing out, not your client. - For long agent turns the answer is resume, not retry: background mode, or the Batch API.
Three timeouts, and the one everybody sets
A single HTTP call has several independent clocks, and conflating them is why "we set a timeout" so often fails to fix anything.
| Clock | Measures | Right value for LLM calls |
|---|---|---|
| Connect | TCP and TLS handshake | Short. 5 to 10 seconds. A slow handshake is a network fault, not a slow model |
| Read | Gap between successive bytes | Generous while streaming, since gaps are short even on long generations |
| Total | Whole request, first byte to last | The one that must match your product, not your patience |
| Pool | Waiting for a free connection | Short. Exhaustion here is a concurrency bug |
Getting this wrong in the usual direction, one large total timeout and nothing else, means a request to a black-holed host waits the full total before failing, when a five-second connect timeout would have failed it immediately and let a retry succeed.
| Client | Connect | Read | Total |
|---|---|---|---|
| OpenAI Python SDK | 5s | n/a | 600s, 2 retries |
| Anthropic Python SDK | 5s | n/a | 600s, 2 retries |
| Anthropic TypeScript SDK | 600s minimum, scaling with max_tokens up to 60 minutes | ||
Python httpx | 5s | 5s | 5s (all four phases) |
Python requests | none | none | none |
Node fetch / undici | 10s | 300s body, 300s headers | none |
The layer that actually killed it
Here is the crux. Both major SDKs wait ten minutes; almost nothing between you and them does. Line up the real numbers and the winner is obvious.
| Layer | Default | Status on breach | Raisable? |
|---|---|---|---|
| AWS ALB idle timeout | 60s | 504 | Yes, 1 to 4000s |
nginx proxy_read_timeout | 60s | 504 | Yes |
| Cloudflare Proxy Write Timeout | 30s | 524 | No |
| Cloudflare Proxy Read Timeout | 125s | 524 | Enterprise only, up to 6,000s |
| Vercel functions | 300s | Function timeout | Pro and Enterprise to 800s, 1800s in beta |
| Cloud Run request timeout | 300s | 504 | Yes, to 3,600s |
| OpenAI / Anthropic SDK | 600s | APITimeoutError | Yes |
| Cloudflare Proxy Idle Timeout | 900s | 520 | No |
The failure shape tells you which layer without any instrumentation:
| What you see | Who did it |
|---|---|
APITimeoutError from the SDK | Your client. You own this number |
| Cloudflare-branded 524 HTML page | Cloudflare, at 125s of read silence |
| Cloudflare-branded 502 or 504 | Your origin returned it |
| Unbranded blank 502 or 504 | Cloudflare itself generated it |
504 with a JSON body and timeout_error | Anthropic's own server-side timeout |
| Connection reset with no status | A load balancer or middlebox dropped the socket |
| 522 | Cloudflare could not reach your origin at all |
That branded-versus-unbranded distinction for 502 and 504 is one of the more useful facts in Cloudflare's documentation and almost nobody knows it.
Streaming is not an optimisation, it is the fix
Most intermediate timeouts are inactivity timeouts, not duration limits. Cloudflare defines the Proxy Read Timeout precisely as "a timeout value between two successive read operations to your origin server". So a response emitting tokens every few hundred milliseconds resets that clock continuously and can run far longer than 125 seconds. A non-streaming request producing nothing for three minutes cannot.
Anthropic enforces the same conclusion from the other end, and does it in the client so you cannot get it wrong quietly:
The user-facing wording of that guard is Streaming is required for operations that may take longer than 10 minutes. The TypeScript SDK takes a different route to the same place, scaling the default timeout with max_tokens up to sixty minutes rather than refusing. And the API side has its own dedicated status for this: a 504 timeout_error, documented as "the request timed out while processing", with the recommendation to use the streaming Messages API for long-running requests.
with client.messages.stream(
model="claude-sonnet-5",
max_tokens=64000,
messages=messages,
) as stream:
message = stream.get_final_message() # identical to a non-streaming result
Timeouts worth setting, by operation
One global timeout cannot serve an autocomplete and a repository-wide refactor. Set them per operation, and set them from the product requirement rather than from the model.
| Operation | Connect | Total | Stream? | Retries |
|---|---|---|---|---|
| Classification, extraction, short answers | 5s | 30s | No | 2 |
| Chat turn with a human waiting | 5s | 120s | Yes | 1 |
| Reasoning at high effort | 5s | 600s | Yes | 1 |
| Agent turn with tool calls | 5s | 900s per turn | Yes | 0, resume instead |
| Long document generation | 5s | SDK default | Required | 1 |
| Bulk offline work | n/a | n/a | n/a | Use the Batch API |
from openai import OpenAI
import httpx2
client = OpenAI(
timeout=httpx2.Timeout(120.0, connect=5.0),
max_retries=2,
)
# a specific call that legitimately needs longer
resp = client.with_options(timeout=600.0).responses.create(
model="gpt-5.6-sol",
input=big_prompt,
)
- Raise every layer together or none. Raising the SDK timeout to 900 seconds behind a 60 second ALB changes nothing except which error you see.
- Keep the connect timeout short always. It is the one number that should never scale with the work.
- Budget the whole chain. If your API gateway allows 30 seconds, an LLM call inside it cannot have a 120 second timeout in any meaningful sense.
- Do not retry a timeout blind on an agent turn. The turn may have already run tools. This is the same duplicate-execution problem retries cause on 5xx errors.
Retry, or resume?
For a stateless completion, retrying a timeout is correct and cheap. For an agent turn it is neither, because you do not know how far the turn got, and a replay can re-execute side effects that already happened. Past roughly a minute of work, the right pattern stops being retry and becomes resume.
| Pattern | Good for | Cost |
|---|---|---|
| Retry the whole call | Short stateless requests | Duplicate work, duplicate tokens |
| Stream and checkpoint | Long generations | You keep the partial output on a drop |
| Background mode | Long single requests | Higher time to first token; poll or resume by ID |
| Batch API | Anything with nobody waiting | Latency, in exchange for roughly half the price |
| Turn-level checkpointing | Agent loops | You build it, and it is the only thing that really works |
OpenAI documents background mode for exactly this: send background: true, poll while the response is queued or in_progress, and resume a stream from a sequence_number instead of replaying the turn. Two caveats from the same page: time to first token is higher than a synchronous call, and cancellation is idempotent even though the inference endpoints have no idempotency key. There is also a hard ceiling on the WebSocket surface, sixty minutes, with the error Responses websocket connection limit reached (60 minutes). Create a new websocket connection to continue.
Anthropic's equivalent is the Message Batches API, recommended in the errors documentation as the alternative to holding an uninterrupted connection, and priced at half rate in both directions.
Questions people ask
What is the default timeout for the OpenAI and Anthropic APIs?
Both Python SDKs default to 600 seconds total with a 5 second connect timeout, and both retry twice by default. The Anthropic TypeScript SDK uses 600 seconds as a floor and scales it with max_tokens up to sixty minutes. In practice these rarely fire, because something between you and the provider is stricter.
What causes a Cloudflare 524 on an API call?
Cloudflare reached your origin but got no response before the Proxy Read Timeout, which defaults to 125 seconds. Enterprise zones can raise it to 6,000 seconds through a Cache Rule read_timeout setting or the zone settings API; other plans cannot. A separate 30 second Proxy Write Timeout also returns 524 and cannot be adjusted at all.
Does streaming prevent timeout errors?
It prevents most of them. Cloudflare defines its Proxy Read Timeout as a timeout between two successive read operations, so a response emitting tokens continuously keeps resetting that clock. Cloudflare never states outright that streaming prevents a 524, but the definition of the setting points clearly that way, and Anthropic's SDKs go further by refusing a non-streaming request expected to run beyond ten minutes.
Why does my request time out at 60 seconds when I set 600?
Because your timeout is not the binding one. An AWS ALB idles out at 60 seconds by default and nginx reads for 60, so either will kill the connection long before an SDK configured for ten minutes notices. Raising a timeout only helps if you raise every layer between the client and the provider.
Should I retry a timed-out LLM request?
For a short stateless call, yes, and both SDKs already retry timeouts twice by default. For an agent turn, no: the turn may have already executed tools, and replaying it can run those side effects again. Use background mode, the Batch API, or turn-level checkpointing so you can resume rather than restart.
What is the difference between a 504 from Anthropic and a 524 from Cloudflare?
Anthropic's 504 timeout_error is the API server itself giving up while processing, and it arrives as a JSON error body with the documented advice to use the streaming Messages API. A 524 is Cloudflare giving up waiting for an origin, and it arrives as a branded HTML page. If you can see Cloudflare branding, the request never came back from whatever sits behind Cloudflare in your own path.
Sources
Every figure above was read from these pages on August 2026. Vendors reprice without notice; if you find a stale number, tell us.
- Cloudflare error 524 the 125 second Proxy Read Timeout and the Enterprise ceiling
- Cloudflare connection limits every Cloudflare-to-origin timeout and the status each returns
- Claude API errors: long requests 504 timeout_error and the ten-minute streaming guidance
- Anthropic Python SDK default timeout, the non-streaming ValueError guard, TCP keep-alive
- OpenAI background mode polling, stream resumption, idempotent cancellation
- AWS ALB load balancer attributes 60 second idle default and HTTP/2 PING behaviour
- undici Client API Node fetch header, body, and connect timeout defaults