How to Handle Long-Running Requests and Avoid Timeouts in the Anthropic Python SDK
Enable streaming (stream=True) for any request that might exceed 10 minutes, or provide a custom timeout value to bypass the non-streaming guard and handle long-running requests safely.
The Anthropic Python SDK enforces strict timeout defaults to prevent hanging connections, automatically rejecting non-streaming requests that could take longer than 10 minutes. Understanding how to handle long-running requests and potential timeouts is essential for production applications using the anthropics/anthropic-sdk-python repository.
Default Timeout Behavior in the SDK
The SDK initializes every client with a 10-minute default timeout defined in src/anthropic/_constants.py:
# src/anthropic/_constants.py
DEFAULT_TIMEOUT = httpx.Timeout(timeout=10 * 60, connect=5.0) # 600 seconds total
This value propagates to the BaseClient class in src/anthropic/_base_client.py, where it becomes the client-wide timeout unless explicitly overridden during initialization or per-request.
The Non-Streaming Guard for Long-Running Requests
To prevent users from accidentally triggering timeouts, the SDK implements a proactive guard in BaseClient._calculate_nonstreaming_timeout that estimates processing time and forces streaming for long jobs.
How the Guard Calculates Risk
The method assumes a worst-case processing speed of 128,000 tokens per hour (approximately 35 tokens per second). It calculates the expected duration and raises a ValueError if the request exceeds safe thresholds:
# src/anthropic/_base_client.py
def _calculate_nonstreaming_timeout(self, max_tokens: int, max_nonstreaming_tokens: int | None) -> Timeout:
maximum_time = 60 * 60 # 1 hour (theoretical upper bound)
default_time = 60 * 10 # 10 minutes
expected_time = maximum_time * max_tokens / 128_000
if expected_time > default_time or (max_nonstreaming_tokens and max_tokens > max_nonstreaming_tokens):
raise ValueError(
"Streaming is required for operations that may take longer than 10 minutes. "
+ "See https://github.com/anthropics/anthropic-sdk-python#long-requests for more details",
)
return Timeout(default_time, connect=5.0)
Where the Guard Is Applied
The check executes in src/anthropic/resources/messages/messages.py within the create method, but only when three conditions are met:
# src/anthropic/resources/messages/messages.py
if not stream and not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = self._client._calculate_nonstreaming_timeout(
max_tokens, MODEL_NONSTREAMING_TOKENS.get(model, None)
)
This means the guard is bypassed if you explicitly provide a custom timeout or enable streaming.
Strategies to Handle Long-Running Requests
Enable Streaming for Large Generations
Streaming is the recommended approach for any request that might exceed 10 minutes. When stream=True, the SDK returns a Stream object that yields events as they arrive, keeping the connection alive indefinitely:
from anthropic import Anthropic
client = Anthropic()
stream = client.messages.create(
max_tokens=12_000,
model="claude-3-opus-20240229",
messages=[{"role": "user", "content": "Write a comprehensive 50-page technical manual."}],
stream=True, # Bypasses the non-streaming guard
)
for event in stream:
if event.type == "content_block_delta":
print(event.delta.text, end="", flush=True)
Provide a Custom Timeout
To handle long-running requests in non-streaming mode, override the default timeout. Any value different from DEFAULT_TIMEOUT disables the automatic guard:
from anthropic import Anthropic
# Set a 20-minute timeout
client = Anthropic(timeout=1200.0)
response = client.messages.create(
max_tokens=4_000,
model="claude-3-sonnet-20240229",
messages=[{"role": "user", "content": "Generate a detailed legal contract."}],
stream=False,
)
You can also set timeouts per-request using with_options:
response = client.with_options(timeout=900.0).messages.create(
max_tokens=3_000,
model="claude-3-haiku-20240307",
messages=[{"role": "user", "content": "Analyze this 100-page document."}],
)
Reduce max_tokens to Stay Under the Limit
If you prefer non-streaming responses but want to avoid the guard, calculate your token budget to stay under the 10-minute threshold. Based on the SDK's 128k tokens/hour assumption:
- Safe limit: Approximately 21,000 tokens (128,000 ÷ 60 × 10)
- Conservative limit: 20,000 tokens or fewer
# Safe non-streaming request
response = client.messages.create(
max_tokens=20_000, # Under the ~21k token threshold
model="claude-3-opus-20240229",
messages=[{"role": "user", "content": "Summarize quantum computing."}],
stream=False,
)
Adjust Retry Behavior for Timeout Resilience
The SDK automatically retries on timeouts using exponential backoff. You can adjust this behavior via the max_retries parameter (default is 2):
from anthropic import Anthropic
# Increase retries for flaky networks
client = Anthropic(max_retries=5)
# Or disable retries entirely for strict timeout control
client = Anthropic(max_retries=0)
How the SDK Handles Timeout Errors
When a request exceeds its timeout, the SDK implements a sophisticated retry mechanism in BaseClient.request:
- httpx raises
httpx.TimeoutException - The SDK catches this in
src/anthropic/_base_client.pyand checks remaining retries - If retries remain, it calls
_sleep_for_retrywith exponential backoff and jitter - After final attempt, it raises
APITimeoutError:
# src/anthropic/_base_client.py (excerpt)
except httpx.TimeoutException as err:
log.debug("Encountered httpx.TimeoutException", exc_info=True)
if remaining_retries > 0:
self._sleep_for_retry(...)
continue
log.debug("Raising timeout error")
raise APITimeoutError(request=request) from err
Complete Code Examples
Streaming a Massive Generation
from anthropic import Anthropic, APITimeoutError
client = Anthropic()
try:
stream = client.messages.create(
max_tokens=12_000,
model="claude-3-opus-20240229",
messages=[{"role": "user", "content": "Write a 30-page novel about space exploration"}],
stream=True,
)
for event in stream:
if event.type == "content_block_delta":
print(event.delta.text, end="", flush=True)
except APITimeoutError:
print("Even streaming timed out – check network conditions.")
Custom Timeout for Controlled Non-Streaming
from anthropic import Anthropic, APITimeoutError
# 20-minute timeout overrides the default guard
client = Anthropic(timeout=1200.0)
try:
resp = client.messages.create(
max_tokens=3_000,
model="claude-3-sonnet-20240229",
messages=[{"role": "user", "content": "Generate a 15-page research summary."}],
stream=False,
)
print(resp.content)
except APITimeoutError:
print("Request exceeded 20 min – consider streaming or splitting the job.")
Adjusting Retries and Handling Rate Limits
from anthropic import Anthropic, RateLimitError, APITimeoutError
client = Anthropic(max_retries=5) # More aggressive retry policy
try:
result = client.messages.create(
max_tokens=4_000,
model="claude-3-opus-20240229",
messages=[{"role": "user", "content": "Explain quantum computing in depth."}],
stream=False,
)
print(result.content)
except RateLimitError as e:
print(f"Rate limited, wait {e.retry_after}s before retrying")
except APITimeoutError:
print("Operation timed out – maybe split into smaller chunks")
Summary
- Default timeout: The SDK enforces a 10-minute default timeout via
DEFAULT_TIMEOUTinsrc/anthropic/_constants.py. - Non-streaming guard: The
_calculate_nonstreaming_timeoutmethod insrc/anthropic/_base_client.pyraisesValueErrorfor non-streaming requests estimated to exceed 10 minutes. - Streaming solution: Enable
stream=Trueto bypass the guard and handle long-running requests safely without timeout limits. - Custom timeouts: Pass a custom
timeoutvalue (different from the default) to disable the guard for non-streaming requests. - Retry logic: The SDK automatically retries on
APITimeoutErrorwith exponential backoff; adjustmax_retriesto control this behavior.
Frequently Asked Questions
What is the default timeout in the Anthropic Python SDK?
The default timeout is 10 minutes (600 seconds), defined as httpx.Timeout(timeout=10 * 60, connect=5.0) in src/anthropic/_constants.py. This applies to all requests unless you provide a custom timeout during client initialization or per-request.
Why does the SDK force streaming for long requests?
The SDK protects users from accidental timeouts by calculating the expected processing time in BaseClient._calculate_nonstreaming_timeout. If a non-streaming request is estimated to take longer than 10 minutes based on the max_tokens value (assuming 128,000 tokens/hour processing speed), it raises a ValueError requiring you to enable streaming.
How can I disable the non-streaming guard?
You can bypass the guard by providing a custom timeout that differs from DEFAULT_TIMEOUT. For example, initializing the client with Anthropic(timeout=1200.0) disables the check because the guard only triggers when self._client.timeout == DEFAULT_TIMEOUT. Alternatively, use stream=True to avoid the check entirely.
What exception is raised when a request times out?
When a request exceeds its timeout after all retry attempts, the SDK raises APITimeoutError. This exception wraps the underlying httpx.TimeoutException and includes the request details. You can catch this to implement fallback logic, such as switching to streaming or splitting the request into smaller chunks.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →