CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-anthropic

The official Python library for the anthropic API

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

error-handling.mddocs/guides/

Error Handling Guide

Robust error handling patterns for production applications using the Anthropic Python SDK.

Basic Error Handling

from anthropic import APIError

try:
    message = client.messages.create(
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello"}]
    )
except APIError as e:
    print(f"Error: {e.message}")

Specific Error Types

from anthropic import (
    RateLimitError,
    AuthenticationError,
    BadRequestError,
    NotFoundError,
    InternalServerError,
)

try:
    message = client.messages.create(...)
except RateLimitError as e:
    retry_after = e.response.headers.get("retry-after")
    print(f"Rate limited. Retry after {retry_after}s")
except AuthenticationError:
    print("Invalid API key")
except BadRequestError as e:
    print(f"Invalid request: {e.message}")
except NotFoundError:
    print("Resource not found")
except InternalServerError:
    print("Server error, please retry")

Retry with Exponential Backoff

import time
from anthropic import RateLimitError, InternalServerError

def create_message_with_retry(max_retries=3, base_delay=1.0):
    """Create message with exponential backoff retry."""
    for attempt in range(max_retries):
        try:
            return client.messages.create(
                model="claude-sonnet-4-5-20250929",
                max_tokens=1024,
                messages=[{"role": "user", "content": "Hello"}]
            )
        except (RateLimitError, InternalServerError) as e:
            if attempt == max_retries - 1:
                raise

            wait_time = base_delay * (2 ** attempt)
            print(f"Retry {attempt + 1}/{max_retries} after {wait_time}s")
            time.sleep(wait_time)

message = create_message_with_retry()

Advanced Retry Pattern

import random
import time
from anthropic import APIError, RateLimitError

def exponential_backoff_retry(
    func,
    max_retries=5,
    base_delay=1.0,
    max_delay=60.0,
    jitter=True
):
    """
    Execute function with exponential backoff retry.

    Args:
        func: Function to execute
        max_retries: Maximum retry attempts
        base_delay: Initial delay in seconds
        max_delay: Maximum delay in seconds
        jitter: Add random jitter to avoid thundering herd
    """
    for attempt in range(max_retries):
        try:
            return func()
        except RateLimitError as e:
            if attempt == max_retries - 1:
                raise

            # Use retry-after header if available
            retry_after = e.response.headers.get("retry-after")
            if retry_after:
                wait_time = float(retry_after)
            else:
                wait_time = min(base_delay * (2 ** attempt), max_delay)
                if jitter:
                    wait_time *= (0.5 + random.random())

            print(f"Rate limited. Waiting {wait_time:.1f}s (attempt {attempt + 1}/{max_retries})")
            time.sleep(wait_time)
        except APIError as e:
            if attempt == max_retries - 1:
                raise
            print(f"API error: {e.message}. Retrying...")
            time.sleep(base_delay)

# Usage
message = exponential_backoff_retry(
    lambda: client.messages.create(...)
)

Async Error Handling

import asyncio
from anthropic import AsyncAnthropic, APIError

async def create_message_safe():
    client = AsyncAnthropic()

    try:
        message = await client.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello"}]
        )
        return message
    except APIError as e:
        print(f"Error: {e.message}")
        return None

result = asyncio.run(create_message_safe())

Circuit Breaker Pattern

import time
from anthropic import APIError

class CircuitBreaker:
    """Circuit breaker to prevent cascading failures."""

    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.timeout = timeout
        self.last_failure_time = None
        self.is_open = False

    def call(self, func, *args, **kwargs):
        """Execute function with circuit breaker protection."""
        if self.is_open:
            # Check if timeout has passed
            if time.time() - self.last_failure_time < self.timeout:
                raise Exception("Circuit breaker is open")
            else:
                # Try to close circuit
                self.is_open = False
                self.failure_count = 0

        try:
            result = func(*args, **kwargs)
            self.failure_count = 0  # Reset on success
            return result
        except APIError as e:
            self.failure_count += 1
            self.last_failure_time = time.time()

            if self.failure_count >= self.failure_threshold:
                self.is_open = True
                print(f"Circuit breaker opened after {self.failure_count} failures")

            raise

# Usage
circuit_breaker = CircuitBreaker()

try:
    message = circuit_breaker.call(
        client.messages.create,
        model="claude-sonnet-4-5-20250929",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello"}]
    )
except Exception as e:
    print(f"Circuit breaker error: {e}")

Logging Errors

import logging
from anthropic import APIError, APIStatusError

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

try:
    message = client.messages.create(...)
except APIStatusError as e:
    logger.error(
        "API request failed",
        extra={
            "request_id": e.request_id,
            "status_code": e.status_code,
            "error_message": e.message,
            "error_type": e.body.get("error", {}).get("type") if e.body else None,
        }
    )
except APIError as e:
    logger.error(f"API error: {e.message}")

Graceful Degradation

from anthropic import APIError

def get_response_with_fallback(user_message):
    """Try primary model, fall back to simpler model on error."""
    models = [
        "claude-sonnet-4-5-20250929",
        "claude-3-5-haiku-20241022",
    ]

    for model in models:
        try:
            message = client.messages.create(
                model=model,
                max_tokens=1024,
                messages=[{"role": "user", "content": user_message}]
            )
            return message.content[0].text
        except APIError as e:
            print(f"Failed with {model}: {e.message}")
            continue

    return "Service temporarily unavailable"

response = get_response_with_fallback("What is AI?")

Validate Inputs Before API Call

from anthropic import BadRequestError

def validate_and_create_message(messages):
    """Validate inputs before making API call."""
    # Validate message structure
    if not messages:
        raise ValueError("Messages list cannot be empty")

    for msg in messages:
        if "role" not in msg or "content" not in msg:
            raise ValueError("Each message must have 'role' and 'content'")

        if msg["role"] not in ["user", "assistant"]:
            raise ValueError(f"Invalid role: {msg['role']}")

    # Make API call
    try:
        return client.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1024,
            messages=messages
        )
    except BadRequestError as e:
        print(f"API validation failed: {e.message}")
        raise

Best Practices

1. Always Handle Exceptions

Never let exceptions go unhandled in production.

2. Use Specific Exception Types

Catch specific exceptions for targeted handling.

3. Implement Retry Logic

Always retry transient errors (rate limits, server errors).

4. Log with Context

Include request IDs and relevant context in logs.

5. Set Reasonable Timeouts

import httpx

client = Anthropic(
    timeout=httpx.Timeout(60.0),
    max_retries=3
)

6. Monitor Error Rates

Track error rates to detect issues early.

See Also

  • Error Reference - Complete exception hierarchy
  • Client Configuration - Timeout and retry configuration

Install with Tessl CLI

npx tessl i tessl/pypi-anthropic

docs

index.md

tile.json