When working with the Anthropic API, you’ll occasionally run into HTTP errors. Some are simple, like a bad request or an expired API key. Others can be trickier-rate limits, malformed prompts, or server-side issues.
This guide explains the most common Anthropic API HTTP errors, their root causes, how to fix them, and how to prevent them. You’ll also find simplified Python examples to help you build a resilient integration.
Let’s dive in.
1. Understanding Anthropic API Error Categories
Anthropic API errors generally fall into two buckets:
4xx Errors – Client Mistakes
These usually mean your request had a problem:
- malformed JSON
- wrong parameters
- missing/invalid API key
- too many requests
- unauthenticated access
5xx Errors – Server or System Issues
Your request was fine, but Anthropic couldn’t process it due to an internal issue or overload.
See Anthropic’s official docs for reference:
https://platform.claude.com/docs/en/api/errors
2. The Most Common Anthropic HTTP Errors (Explained)
Below you’ll find a breakdown of each major error, why it happens, how to fix it, and prevention tips.
🔸 400 – Bad Request
What it means
Your request is invalid-wrong schema, unsupported parameters, malformed fields. The API also returns 400 for other 4XX conditions not in the documented list, so an unfamiliar 4xx is usually a 400
Common Causes
- Invalid JSON
- Too many parameters
- Wrong field names
- Sending unsupported types (e.g., numbers instead of strings)
- Missing required fields (
max_tokens,model,messages) - Wrong value types (string where an int is expected)
- Invalid tool schema
- Malformed message structure (empty content, wrong role order)
How to Fix
- Validate JSON
- Double-check API reference
- Log request bodies for debugging
Simplified Python Example
try:
client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": 123}], # invalid: content must be str or list
)
)
except Exception as e:
print("Fix your payload:", e)
Model-Specific 400s
Some 400s are not schema errors but capability mismatches between your request and
the model you selected. Current examples from Anthropic’s docs:
- Assistant message prefill is not supported on Claude 4.6 and later.
thinking: {"type": "enabled"}is rejected on Claude 4.7 and later; use
adaptive thinking withoutput_config.effort.thinking: {"type": "adaptive"}is rejected on Claude 4.5 and earlier.thinking: {"type": "disabled"}is rejected on models where thinking is always on.
If a request suddenly starts returning 400 after a model upgrade, check the
parameter set against that model’s docs before debugging your payload.
🔸 401 – Unauthorized
What it means
Your API key is missing, invalid, or expired.
Fix
- Set the correct
ANTHROPIC_API_KEYenvironment variable - Rotate key if compromised
Prevention
- Avoid hardcoding keys
- Use secrets manager
import os
from anthropic import Anthropic
client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
🔸 402 – Billing Error
There is an issue with your billing or payment information. Check payment details
in the Claude Console, or in AWS Marketplace if you are on Claude Platform on AWS.
🔸 403 – Forbidden
You don’t have permission to perform the action.
Causes
- API key lacks permission for the specified resource
- Workspace or organization access restrictions
Fix
- Check your organization’s access and workspace settings in the Claude Console
🔸 404 – Not Found
The endpoint or resource doesn’t exist.
Fix
- Check URLs and model names carefully
- Ensure you’re using a current model ID (e.g.
"claude-sonnet-5"). Retired model strings return 404. Check the models list endpoint for what is currently available.
🔸 409 – Conflict
A request conflicts with the current state.
Example scenarios
- The resource was modified concurrently by another request
- A value that must be unique is already in use
Fix
- Resolve the conflict, then retry
- Serialize writes to the same resource, or use optimistic concurrency
🔸 413 – Request Too Large
The request exceeds the maximum allowed number of bytes. Per-endpoint maximums:
| Endpoint | Max request size |
|---|---|
| Messages API | 32 MB |
| Token Counting API | 32 MB |
| Batch API | 256 MB |
| Files API | 500 MB |
On the direct Claude API, Cloudflare returns this before the request reaches the
API servers.
Fix
- Compress or downscale images before base64 encoding
- Upload large files via the Files API and reference them instead of inlining
- Chunk long documents
🔸 429 – Too Many Requests (Rate Limit)
Anthropic enforces rate limits per model class across three dimensions:
- RPM – requests per minute
- ITPM – input tokens per minute
- OTPM – output tokens per minute
Hitting any one of them returns 429.
There is also a separate acceleration limit: per Anthropic’s docs, a sharp increase
in your organization’s usage can produce 429s even below your steady-state limits.
Ramp traffic gradually and keep usage patterns consistent.
Fix
- Slow down
- Use retry logic
- Cache repeated responses
Python Retry Pattern (simplified)
# Option 1 (preferred): the official SDKs already retry transient failures
# (connection errors, rate limits, 5xx) with exponential backoff - twice by
# default, honoring the retry-after header. Just raise the ceiling:
client = anthropic.Anthropic(max_retries=5)
# Option 2: manual control
import random, time
import anthropic
RETRYABLE = {429, 500, 502, 503, 504, 529}
def call_with_retry(max_attempts=5):
for attempt in range(max_attempts):
try:
return client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
except anthropic.APIStatusError as e:
if e.status_code not in RETRYABLE or attempt == max_attempts - 1:
raise # 400/401/403/404 will never succeed on retry
retry_after = e.response.headers.get("retry-after")
delay = float(retry_after) if retry_after else 2 ** attempt + random.random()
time.sleep(delay)🔹 5xx Errors – Server Problems
These mean the issue is on Anthropic’s side.
Streaming caveat: with server-sent events, an error can occur after the API has
already returned 200. Those mid-stream errors do not follow the standard status
code mechanism – handle SSEerrorevents separately from HTTP status codes.
529 – overloaded_error
What it means
The API is temporarily overloaded. Per Anthropic’s docs, 529s can occur when the
API experiences high traffic across all users – it is not about your account.
429 vs 529
- 429 rate_limit_error = your account hit its own limit. Fix: slow down, spread load,
or request higher limits. - 529 overloaded_error = capacity issue on Anthropic’s side. Fix: back off and retry.
Fix
- Exponential backoff with jitter
- Do not rotate keys or change plans – neither affects 529
- Check status.claude.com before deeper debugging
500 – Internal Server Error or api_error
An unexpected internal error. Retry with exponential backoff. If it persists,
contact support with the request ID.
502 – Bad Gateway
504 – timeout_error
The request timed out while processing. Use the streaming Messages API or the
Message Batches API for long-running requests instead of retrying as-is.
503 – Service Unavailable
Fix/Prevention
- Retry with exponential backoff
- Log these events
- Do not spam retries
def safe_call():
for attempt in range(3):
try:
return client.messages.create(model="claude-sonnet-5", messages=[...])
except Exception:
time.sleep(2 ** attempt)
return None
Request IDs: The Thing Support Will Ask For
Every API response includes a request-id header, e.g. req_018EeWyXxfu5pfWkrYcMdjWG.
The same value appears as request_id in error response bodies. Log it on every
failure – it is the first thing Anthropic support asks for.
Error bodies always return JSON with a top-level error object containing type
and message:
{
"type": "error",
"error": {
"type": "not_found_error",
"message": "The requested resource could not be found."
},
"request_id": "req_011CSHoEeqs5C35K2UUqR7Fy"
}
The Python and TypeScript SDKs expose it as _request_id on response objects.
3. Summary Table
| Status | Error type | Root cause | Quick fix | Retry? |
|---|---|---|---|---|
| 400 | invalid_request_error | Bad payload, wrong types, model mismatch | Validate schema and model params | No |
| 401 | authentication_error | Key missing, malformed, revoked, expired | Set or rotate ANTHROPIC_API_KEY | No |
| 402 | billing_error | Payment or billing issue | Check billing in Console | No |
| 403 | permission_error | Key lacks access to the resource | Check workspace/org settings | No |
| 404 | not_found_error | Wrong endpoint or retired model ID | Fix path or model ID | No |
| 409 | conflict_error | Concurrent modification or uniqueness violation | Resolve, then retry | After fix |
| 413 | request_too_large | Payload over the endpoint limit | Compress, chunk, or use Files API | No |
| 429 | rate_limit_error | Your RPM/ITPM/OTPM limit hit | Backoff, throttle, raise limits | Yes |
| 500 | api_error | Anthropic internal error | Backoff, log request ID | Yes |
| 504 | timeout_error | Request timed out processing | Use streaming or Batches API | Restructure |
| 529 | overloaded_error | Anthropic-wide capacity saturation | Backoff with jitter, check status page | Yes |
4. Best Practices for Stable Anthropic API Integrations

✔ Validate inputs before sending
Ensure data types match Anthropic’s schema.
✔ Implement retry logic with backoff
Especially for 429 & 5xx errors.
✔ Cache repeated responses
Reduces both cost and rate-limit pressure.
✔ Log errors with request context
Essential for debugging.
✔ Monitor usage
Watch token usage to avoid hitting quotas unexpectedly.
5. Python Error Handling Template (Simplified)
import anthropic, logging
def call_claude(prompt):
try:
return client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
except anthropic.APIStatusError as e:
logging.error(
"Claude API error: status=%s type=%s request_id=%s",
e.status_code,
getattr(e.body, "get", lambda k: None)("type"),
e.request_id,
)
raise
except anthropic.APIConnectionError as e:
logging.error("Connection error: %s", e)
raise

Leave a Reply