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:

  1. httpx raises httpx.TimeoutException
  2. The SDK catches this in src/anthropic/_base_client.py and checks remaining retries
  3. If retries remain, it calls _sleep_for_retry with exponential backoff and jitter
  4. 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_TIMEOUT in src/anthropic/_constants.py.
  • Non-streaming guard: The _calculate_nonstreaming_timeout method in src/anthropic/_base_client.py raises ValueError for non-streaming requests estimated to exceed 10 minutes.
  • Streaming solution: Enable stream=True to bypass the guard and handle long-running requests safely without timeout limits.
  • Custom timeouts: Pass a custom timeout value (different from the default) to disable the guard for non-streaming requests.
  • Retry logic: The SDK automatically retries on APITimeoutError with exponential backoff; adjust max_retries to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →