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:

bash
{
  "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.typeHTTPWhat happenedRetry?
invalid_request_error400Malformed request or parametersNo, fix the request
authentication_error401Wrong or missing keyNo, check the key
billing_error402A billing or balance problemNo, top up the balance
permission_error403The key may not use a resource, e.g. a modelNo, change key or model
not_found_error404Wrong path or unknown modelNo, check URL and model name
request_too_large413Request exceeds the allowed sizeNo, shrink the request
rate_limit_error429A limit was exceededDepends on the cause, see below
api_error500Internal server errorYes, with a pause
timeout_error504The request timed out while processingYes; for long answers turn on streaming
overloaded_error529Service is overloadedYes, 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

HTTPReason in ZukkoWhat to do
401Wrong keyCheck the fetch_... key and the header
402Not enough balanceTop up the balance in the dashboard
403model_not_allowed_for_key: the model is not in the key's allowed listAdd the model to the key's allowed_models or use another key
404model_not_found: unknown model nameCompare with GET /v1/models
413Request too largeShorten the context
429Key daily or monthly limit, or a provider limitLook at the code in the response body
503Provider 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.

bash
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

  1. URL. For the Anthropic SDK and Claude Code the base URL is https://api.zukko.pro without /v1; for OpenAI-format clients it is https://api.zukko.pro/v1.
  2. Key and headers. Authorization: Bearer fetch_... or x-api-key (the SDK sends it itself), plus anthropic-version: 2023-06-01 on direct calls.
  3. Model name. Compare with the response of GET https://api.zukko.pro/v1/models: models appear and get disabled.
  4. Balance and key limits. Balance and spending are visible in the dashboard, as are the key's daily and monthly limits.
  5. 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:

bash
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.

Get API keyDocumentation

api.zukko.pro · fetch_*

Claude API error: error types and what to do with each · Zukko