The most natural way to call the Claude API is also the most fragile for long work: send a request, block, and wait for the complete response in one piece. Anthropic's error documentation draws a clear line here — for requests that may take longer than about 10 minutes, you should use streaming or the Message Batches API. This is not a soft suggestion. A non-streaming HTTP request has to hold a single silent connection open for the entire generation, and long-lived silent connections fail: the API itself can return a 504 timeout_error, and every load balancer, proxy, and corporate firewall between you and Anthropic gets its own veto.
The SDK stops you before the API does
Anthropic's official SDKs bake this rule in. Before sending a non-streaming request, the SDK validates that it isn't likely to exceed the 10-minute timeout — a request shaped to run longer (think: a very large max_tokens on a slow, thorough model) gets rejected client-side rather than being allowed to die quietly at minute eleven. The SDKs also enable TCP keep-alive on the socket, which reduces the chance that idle-connection timeouts along the network path kill a legitimate request early. If you've ever wondered why the Python SDK complains about a large max_tokens on a plain messages.create() call, this is the mechanism you're hitting.
The fix is usually one parameter:
from anthropic import Anthropic
client = Anthropic()
with client.messages.stream(
model="claude-opus-4-8",
max_tokens=64000,
messages=[{"role": "user", "content": "Write the full migration plan..."}],
) as stream:
for text in stream.text_stream:
handle(text)
Streaming changes the failure math entirely. Instead of one long silence, the connection carries a steady flow of server-sent events, with ping events filling any quiet gaps — so intermediaries see traffic, and your application sees progress it can checkpoint.
Choosing between streaming and batch
Both escape routes solve the timeout; they suit different jobs.
| Streaming | Message Batches API | |
|---|---|---|
| Best for | Interactive or single long-running requests where someone (or something) is waiting | High-volume offline work with no one waiting |
| Latency | Tokens arrive as generated | Most batches finish in under 1 hour; a batch expires if not done within 24 hours |
| Price | Standard per-token rates | 50% of standard API prices |
| Scale | One response per connection | Up to 100,000 requests or 256 MB per batch |
The batch route has a bonus property for resilience planning: expired requests are not billed, and each request in the batch reports its own result type (succeeded, errored, canceled, or expired), with only succeeded requests charged. Note that batches themselves refuse stream: true inside individual requests — the two mechanisms don't nest.
The 3P wrinkle: not every platform has Anthropic's Batch API
On third-party platforms, the streaming half of this advice travels everywhere — streaming is available on Claude Platform on AWS, Amazon Bedrock, Google Vertex AI, and Microsoft Foundry. The batch half does not. Anthropic's Message Batches API is available on the Claude API and Claude Platform on AWS, but not on Bedrock or Vertex AI, and not at all on Foundry. That doesn't leave AWS and Google customers without an offline lane: both clouds offer their own batch inference mechanisms for Claude (S3-based on Bedrock, BigQuery/GCS-based on Vertex with 50% batch pricing) — different plumbing from Anthropic's endpoint, same "no one is waiting, so don't hold a connection open" principle. Long-running synchronous calls on Bedrock have an additional platform-specific trap covered in the Bedrock read-timeout article: the model may be allowed 60 minutes, but the AWS SDK's default read timeout is one minute.
Where to go next
See batch vs. real-time for the workload-level decision, batch processing for the mechanics of Anthropic's endpoint, and SDK timeout tuning for adjusting client-side timeouts when you stay synchronous.