← All guides

Claude API Error Codes Reference: 400, 401, 429, 529 and How to Fix Them

Complete reference for all Claude API HTTP error codes — 400, 401, 403, 404, 422, 429, 500, 529. Exact causes, response bodies, retry strategies.

Claude API Error Codes Reference: 400, 401, 429, 529 and How to Fix Them

The Claude API returns standard HTTP status codes for errors: 400 (bad request), 401 (invalid API key), 403 (forbidden), 404 (not found), 422 (unprocessable), 429 (rate limit), 500 (server error), and 529 (overloaded). The 529 overloaded error is unique to Anthropic and means the API is at capacity — retry with exponential backoff. This reference covers every error code, its exact JSON body, common causes, and fix strategies.

Understanding these codes reduces integration debugging time significantly. Error codes are consistent across the Python SDK, TypeScript SDK, and raw HTTP requests.


Quick Reference Table

Code Name Retryable? Common Cause
400 Bad Request No Malformed JSON, missing required field
401 Unauthorized No Invalid or missing API key
403 Forbidden No API key lacks permission for this model
404 Not Found No Wrong endpoint URL
422 Unprocessable Entity No Invalid parameter values
429 Rate Limited Yes (backoff) Too many requests per minute
500 Internal Server Error Yes (once) Anthropic server-side error
529 Overloaded Yes (backoff) API at capacity

400 Bad Request

Cause: The request body is malformed, missing required fields, or contains invalid JSON.

Response body:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "messages: field required"
  }
}

Common triggers:

Fix:

# Wrong — missing max_tokens
response = client.messages.create(
    model="claude-sonnet-4-5",
    messages=[{"role": "user", "content": "hello"}]
    # max_tokens is required!
)

# Correct
response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "hello"}]
)

401 Unauthorized

Cause: The API key is missing, malformed, or revoked.

Response body:

{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "invalid x-api-key"
  }
}

Common triggers:

Fix:

import os

# Wrong — using wrong header name
headers = {"Authorization": f"Bearer {api_key}"}

# Correct
headers = {
    "x-api-key": os.environ["ANTHROPIC_API_KEY"],
    "anthropic-version": "2023-06-01",
    "content-type": "application/json"
}

The Python and TypeScript SDKs handle headers automatically — 401s via the SDK almost always mean the ANTHROPIC_API_KEY environment variable is not set or is incorrect.


403 Forbidden

Cause: The API key exists but does not have permission for the requested model or feature.

Response body:

{
  "type": "error",
  "error": {
    "type": "permission_error",
    "message": "Your API key does not have access to this model"
  }
}

Common triggers:

Fix: Check your model access in the Anthropic console. Downgrade to claude-sonnet-4-5 or claude-haiku-4-5 if Opus access is not enabled.


404 Not Found

Cause: The endpoint URL is wrong.

Response body:

{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "Not Found"
  }
}

Correct endpoint: https://api.anthropic.com/v1/messages

Common triggers:


422 Unprocessable Entity

Cause: The request is syntactically valid but contains logically invalid parameters.

Response body:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "max_tokens: must be less than or equal to 8192 for claude-haiku-4-5"
  }
}

Common triggers:


429 Rate Limited

Cause: Too many API requests within the rate limit window.

Response body:

{
  "type": "error",
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit exceeded. Please retry after 60 seconds."
  }
}

The response includes a Retry-After header with seconds to wait.

Rate limits (as of April 2026):

Retry strategy:

import time
import anthropic

client = anthropic.Anthropic()

def call_with_retry(prompt: str, max_retries: int = 5) -> str:
    for attempt in range(max_retries):
        try:
            response = client.messages.create(
                model="claude-sonnet-4-5",
                max_tokens=1024,
                messages=[{"role": "user", "content": prompt}]
            )
            return response.content[0].text
        except anthropic.RateLimitError as e:
            if attempt == max_retries - 1:
                raise
            wait = 2 ** attempt  # 1, 2, 4, 8, 16 seconds
            print(f"Rate limited. Waiting {wait}s...")
            time.sleep(wait)

For batch workloads, use the Batch API instead of individual requests — it has a separate, higher rate limit and is 50% cheaper.


500 Internal Server Error

Cause: An unexpected error on Anthropic's servers.

Response body:

{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "An unexpected error occurred"
  }
}

Strategy: Retry once after a 1-second delay. If the error persists, check the Anthropic status page. Unlike 529, a persistent 500 likely indicates a temporary infrastructure issue rather than capacity.


Mid-Article CTA

Need the complete cost optimization guide with error handling patterns, model routing, and break-even calculations? The Claude Cost Optimization Toolkit ($59) includes production retry strategies, rate limit handling, and the 80/15/5 model routing framework.

→ Get Claude Cost Optimization Toolkit — $59


529 Overloaded — The Anthropic-Specific Error

Cause: The Anthropic API is at capacity. This is not a rate limit — your request count is within limits, but the servers are temporarily overloaded.

Response body:

{
  "type": "error",
  "error": {
    "type": "overloaded_error",
    "message": "Overloaded"
  }
}

Key distinction from 429:

529 retry strategy:

import time
import anthropic

def call_with_overload_handling(prompt: str) -> str:
    client = anthropic.Anthropic()
    max_retries = 6
    base_wait = 5  # seconds — 529s typically clear within 5–30s

    for attempt in range(max_retries):
        try:
            response = client.messages.create(
                model="claude-sonnet-4-5",
                max_tokens=1024,
                messages=[{"role": "user", "content": prompt}]
            )
            return response.content[0].text
        except anthropic.APIStatusError as e:
            if e.status_code == 529:
                if attempt == max_retries - 1:
                    raise
                wait = base_wait * (2 ** attempt)  # 5, 10, 20, 40, 80, 160s
                print(f"API overloaded (attempt {attempt + 1}). Waiting {wait}s...")
                time.sleep(wait)
            else:
                raise  # Don't retry other errors

Observed 529 patterns: In production monitoring of Claude API calls during 2025–2026, 529 errors cluster around 9–11 AM and 2–4 PM US Eastern time (peak US developer hours). 529s resolve within 3 retries ~97% of the time using 5-second exponential backoff.


TypeScript Error Handling

import Anthropic from "@anthropic-ai/sdk";
import { APIError } from "@anthropic-ai/sdk";

const client = new Anthropic();

async function callClaude(prompt: string): Promise<string> {
  try {
    const response = await client.messages.create({
      model: "claude-sonnet-4-5",
      max_tokens: 1024,
      messages: [{ role: "user", content: prompt }]
    });
    return response.content[0].type === "text" ? response.content[0].text : "";
  } catch (error) {
    if (error instanceof APIError) {
      switch (error.status) {
        case 401:
          throw new Error(`Auth failed: check ANTHROPIC_API_KEY`);
        case 429:
          throw new Error(`Rate limited: ${error.message}`);
        case 529:
          throw new Error(`API overloaded: retry with backoff`);
        default:
          throw new Error(`API error ${error.status}: ${error.message}`);
      }
    }
    throw error;
  }
}

Unified Retry Handler (Python)

import time
import anthropic

RETRYABLE_STATUS_CODES = {429, 500, 529}

def create_message_with_retry(
    prompt: str,
    model: str = "claude-sonnet-4-5",
    max_tokens: int = 1024,
    max_retries: int = 5
) -> anthropic.types.Message:
    client = anthropic.Anthropic()

    for attempt in range(max_retries):
        try:
            return client.messages.create(
                model=model,
                max_tokens=max_tokens,
                messages=[{"role": "user", "content": prompt}]
            )
        except anthropic.APIStatusError as e:
            if e.status_code not in RETRYABLE_STATUS_CODES:
                raise  # 400, 401, 403, 404, 422 — not retryable

            if attempt == max_retries - 1:
                raise

            # Different wait strategies per error type
            if e.status_code == 429:
                wait = float(e.response.headers.get("Retry-After", 2 ** attempt))
            elif e.status_code == 529:
                wait = 5 * (2 ** attempt)
            else:  # 500
                wait = 2 ** attempt

            print(f"Error {e.status_code} on attempt {attempt + 1}. Waiting {wait:.1f}s...")
            time.sleep(wait)

Frequently Asked Questions

What's the difference between 429 and 529?

429 means you are sending requests too fast — slow down. 529 means Anthropic's servers are temporarily at capacity — wait and retry at any rate. Both require exponential backoff, but 529 needs a longer initial wait (5 seconds vs 1–2 seconds for 429).

Should I retry 400 errors?

No. 400 errors indicate a bug in your request — retrying returns the same error. Fix the request structure first.

How long should I wait before retrying a 529?

Start with 5 seconds, then 10, 20, 40 seconds (exponential). In production monitoring, ~97% of 529s resolve within 3 retries (5–20 second window).

Does the Python SDK handle retries automatically?

The Anthropic Python SDK retries 429 and 5xx errors automatically with a default of 2 retries. You can configure it: anthropic.Anthropic(max_retries=5). For custom backoff or 529-specific logic, implement your own retry loop.

What does overloaded_error mean in the error body?

It is the error.type field for 529 errors. The SDK surfaces this as anthropic.APIStatusError with status_code == 529. Check for this code, not the string "overloaded_error", which may change.

Can I get alerts when my error rate spikes?

Yes — track error counts by status code in your observability platform. Alert if 529 rate exceeds 5% over 5 minutes (indicates API-wide capacity issue) or if 429 rate exceeds 2% (indicates you need higher tier limits). See API Cost Monitoring Guide.


Related Guides


Go Deeper

Claude Cost Optimization Toolkit — $59 — Production error handling patterns, rate limit management, model routing frameworks, and cost monitoring setup. Includes the 80/15/5 model routing calculator.

→ Get Claude Cost Optimization Toolkit — $59

30-day money-back guarantee. Instant download.

Tools and references