Claude API error: Anthropic-format error types and what to do
A table of Messages API errors: what each type means, which HTTP code arrives through the gateway, what to retry with a pause and what to fix in the request.
5 min · · errors · API keys
When the Claude API returns an error, the first thing worth knowing is whether it is a failure that will pass by itself or a request you must fix. Below is a breakdown of Messages API error types (Anthropic format), the matching HTTP codes when working through the Zukko gateway, and a ready-made handler in Python. If you searched for what to do when "the Claude API is not working", there is a five-step checklist at the end.
What an error looks like in the Anthropic format
When you call POST https://api.zukko.pro/v1/messages, an error arrives with a 4xx or 5xx HTTP status and a body like this:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "max_tokens: field required"
}
}error.type gives the category and message explains details. Use both: the type tells you what to do, the text tells you which field or parameter is at fault.
Error types
error.type | HTTP | What happened | Retry? |
|---|---|---|---|
invalid_request_error | 400 | Malformed request or parameters | No, fix the request |
authentication_error | 401 | Wrong or missing key | No, check the key |
billing_error | 402 | A billing or balance problem | No, top up the balance |
permission_error | 403 | The key may not use a resource, e.g. a model | No, change key or model |
not_found_error | 404 | Wrong path or unknown model | No, check URL and model name |
request_too_large | 413 | Request exceeds the allowed size | No, shrink the request |
rate_limit_error | 429 | A limit was exceeded | Depends on the cause, see below |
api_error | 500 | Internal server error | Yes, with a pause |
timeout_error | 504 | The request timed out while processing | Yes; for long answers turn on streaming |
overloaded_error | 529 | Service is overloaded | Yes, with a pause |
These are types from Anthropic's documentation (which also describes the rare conflict_error with code 409). Through the gateway, Zukko's own codes are added; the HTTP status remains the most reliable guide.
Gateway codes and what stands behind them
| HTTP | Reason in Zukko | What to do |
|---|---|---|
| 401 | Wrong key | Check the fetch_... key and the header |
| 402 | Not enough balance | Top up the balance in the dashboard |
| 403 | model_not_allowed_for_key: the model is not in the key's allowed list | Add the model to the key's allowed_models or use another key |
| 404 | model_not_found: unknown model name | Compare with GET /v1/models |
| 413 | Request too large | Shorten the context |
| 429 | Key daily or monthly limit, or a provider limit | Look at the code in the response body |
| 503 | Provider unavailable or model disabled (model_disabled) | Retry later or switch to another model |
The exact error.type for codes like 402 or 503 depends on the implementation, so do not tie logic to the type string where an HTTP status exists: check a real response on your own key. While 529 and 503 in your logs look like temporary failures, handle them the same way: pause and retry.
Details on individual cases: error 401 and error 529 overloaded.
What to retry and what to fix
The rule is simple. 4xx (except some 429s) means the problem is in your request or key; a retry returns the same answer and just costs time. 5xx and 529 mean a temporary failure, and a retry with exponential backoff is justified. 429 needs sorting out: a provider-side limit passes, an exhausted key limit (key_daily_limit_reached or key_monthly_limit_reached) does not.
A special case is streaming. In streaming mode the server has already answered 200 and started emitting events, so a failure mid-response arrives not as an HTTP code but as an error event inside the stream. If you only handle exceptions when creating the request, you can miss it.
A handler in Python
The official Anthropic SDK retries some requests itself, but it is still handier to sort causes explicitly. Note: for the Anthropic SDK base_url is written without /v1; the SDK adds the path itself.
import os
import time
import anthropic
client = anthropic.Anthropic(
base_url="https://api.zukko.pro",
api_key=os.environ["ZUKKO_API_KEY"],
max_retries=0,
)
def ask(prompt: str, attempts: int = 5) -> str:
for attempt in range(attempts):
try:
msg = client.messages.create(The decision is made on status_code, not on the exception class: the SDK's set of classes changes between versions (for example, recent versions have a separate OverloadedError for 529 that does not inherit from InternalServerError), while the HTTP status is stable.
Claude API is not working: five checks
- URL. For the Anthropic SDK and Claude Code the base URL is
https://api.zukko.prowithout/v1; for OpenAI-format clients it ishttps://api.zukko.pro/v1. - Key and headers.
Authorization: Bearer fetch_...orx-api-key(the SDK sends it itself), plusanthropic-version: 2023-06-01on direct calls. - Model name. Compare with the response of
GET https://api.zukko.pro/v1/models: models appear and get disabled. - Balance and key limits. Balance and spending are visible in the dashboard, as are the key's daily and monthly limits.
- Provider status. If all of the above is fine and 5xx keep coming, check Anthropic's status page and retry later or switch to another model.
A quick check from the terminal:
curl -i https://api.zukko.pro/v1/messages \
-H "Authorization: Bearer fetch_your_key" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-sonnet-5-5","max_tokens":50,"messages":[{"role":"user","content":"ping"}]}'The -i flag shows the HTTP status and headers along with the body. Request format details are in the Messages API reference; keys and headers are covered in the authentication section.
FAQ
How is overloaded_error different from 429?
overloaded_error (529) means the service as a whole is overloaded; you are not the cause. 429 means a limit was exceeded: your key's or the provider's. Both call for a pause, but a key limit is not cured by retrying.
Why does invalid_request_error keep coming back?
Because the request is wrong and the server will answer the same way. Read error.message: often it is a missing max_tokens, a malformed messages structure, or a parameter the model does not accept.
An error arrived in the middle of streaming. Is that normal?
Yes, in a stream the error is delivered as an error event because the HTTP status was already 200. Handle such events and repeat the whole request.
Where can I see what was charged and why it failed?
In the dashboard under "Usage" and through the API (/usage). You can create a separate key per project and restrict it to specific models in the keys section.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- OpenAI API Keys in the Open: Why You Should Not Use ThemWhere free keys on GitHub come from, why using them is dangerous for you and for the owner, and how to protect your own key from the same leak.
- GLM API Errors: Why the Request Fails and How to Fix ItA wrong model id, an overflowing 128K context, the key, the balance, limits: the typical causes of GLM API errors and a quick way to find yours.
- This organization has been disabled in the Claude API: What to DoAn Anthropic key suddenly answers "organization has been disabled". What the error is, what to check, and how to move the SDK and Claude Code to another provider.
- Gemini API not working: region, key, limits and model nameStep-by-step Gemini API diagnostics: from checking status and region to a leaked key, 429 and 503 errors and a typo in the model name.