Claude API errors: 401, 404, 429 and 529, diagnosed

Almost every Claude API error reduces to four causes: the wrong auth header, a doubled version segment in the URL, a missing required parameter, or a model ID that does not exist on the endpoint. Check those before anything else.

In short: Most Claude API errors reduce to four causes: the wrong auth header (use x-api-key), a doubled /v1 in the base URL, a missing max_tokens parameter, or a model ID that does not match the endpoint's list. Check those before anything else.
Confirm the key works first. One command, no SDK, costs nothing:
Don't have an account yet? You need an API key from the gateway before the steps below will work — how the discount works and what you take on. Create one free → (no prepay, $1 minimum top-up)
curl https://aicomp.ai/v1/models \
  -H "Authorization: Bearer sk-your-gateway-key"

A JSON list of model IDs means the key is good. Invalid token means it was copied wrong.

Fast diagnosis table

Status / errorUsual causeFix
401 authentication_errorWrong or truncated key, or wrong headerUse x-api-key and include anthropic-version
404 not_found_errorDoubled /v1, or unknown modelCheck the base URL and the exact model ID
400 invalid_request_errormax_tokens missingAdd it — it is required on this API
429 rate_limit_errorYour quota on requests or tokensExponential backoff with jitter
529 overloaded_errorUpstream under loadRetry with backoff; not your quota
413 / context lengthPrompt longer than the windowCompact history or trim context
500 api_errorServer-side faultRetry once, then alert if it persists

401 (the header), not the key

The single most common failure when moving from an OpenAI-shaped integration. This API expects:

curl https://aicomp.ai/v1/messages \
  -H "x-api-key: $API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-5","max_tokens":64,
       "messages":[{"role":"user","content":"say OK"}]}'

Sending Authorization: Bearer instead returns 401 even with a perfectly valid key.

404 — the doubled segment

If your base URL ends in /v1 and your client appends /v1/messages, the request becomes /v1/v1/messages. Remove the suffix from whichever side is duplicating it, never from both.

400 — required parameters

max_tokens is mandatory. Requests that omit it are rejected before anything else is evaluated, which is why this error can appear even when everything else is correct.

429 and 529 — retries done properly

import time, random

def with_retry(fn, retries=5):
    delay = 1.0
    for _ in range(retries):
        try:
            return fn()
        except RateLimitError:
            time.sleep(delay + random.uniform(0, 0.3))
            delay *= 2
    raise

Never retry a 400 It will fail identically every time. Retry 429, 529 and 500. See rate limits explained for the full picture.

Model not found

Model IDs differ between providers and sometimes include date suffixes. Copy the exact string from the endpoint's own listing rather than from documentation or memory:

curl https://aicomp.ai/v1/models -H "Authorization: Bearer sk-your-gateway-key"

Still stuck

Reproduce with curl from the same machine your app runs on. If curl works and your app does not, the problem is in your client, headers, base URL, or an environment variable that never reached the process.

Error codes, what they actually mean, and how to confirm each

SymptomWhat is actually happeningHow to confirmFix
401 on every call, including a plain curlThe key is wrong, truncated, or from a different account than you think.Run one curl with the key printed to stdout first (whitespace is invisible in most editors).Regenerate the key and paste it straight from the dashboard with no surrounding spaces.
403 with a valid-looking keyAuthentication passed but authorisation did not, the account may be out of credit or restricted.Check account state in the dashboard; the response body often names the reason.Top up or lift the restriction; no client-side change will fix it.
404 with a doubled /v1 in the pathThe base URL already ends in /v1 and the client appended another segment.Read the path in the error message The duplication is visible in it.Remove the suffix from the base URL and let the client build the path.
404 that is actually an HTML pageSomething between you and the endpoint answered instead of the API.Inspect the content type of the response body, HTML means it is not the API.Check proxies and DNS on the host making the call.
429 under load, then fine a minute laterA per-minute window was exhausted, not a permanent cap.Plot the errors against requests per minute.Throttle on the client and back off with jitter rather than retrying immediately.
500 or overloaded responses, intermittentlyUpstream saturation. Retrying instantly adds to it.Check whether error rate rises after retries It usually does.Back off exponentially, and treat persistent 5xx as a signal to change model or route.
Context length error on a request that used to workThe conversation grew past the window; history, tool output and retrieved docs all count.Compare the reported token count against the model's window.Compress or reset the session, and trim what you attach per turn.
Timeouts only when streamingA stream holds the connection open; a timeout tuned for non-streaming calls fires early.Compare wall-clock duration of a stream against your configured timeout.Set a read timeout appropriate to streaming, not a single global timeout.

How to confirm the change actually took effect

"I set it and nothing happened" is the most common failure here, and it is almost never the endpoint. It is usually the client: a desktop app that reads its own settings file rather than your shell environment, a process started before you exported the variable, or an SDK client instance built once at import time and reused after the config changed. Verify before you debug anything else.

Layer 1, is the endpoint reachable, and does your key work?

curl -s https://aicomp.ai/v1/models \
  -H "Authorization: Bearer $KEY" | head -c 400

A JSON list of model IDs means both are true. An Invalid token body means the endpoint answered but rejected the credential The URL is right, the key is not. An HTML page means something between you and the endpoint (a corporate proxy, a captive portal) answered instead, and no amount of config change will fix it from inside your app.

Layer 2 — who actually answered?

from openai import OpenAI
client = OpenAI(base_url="https://aicomp.ai/v1", api_key=KEY)

r = client.chat.completions.create(
    model="gpt-5.6-luna",
    messages=[{"role": "user", "content": "Reply with the single word: ok"}],
    max_tokens=8,
)
print(r.model)          # 回显的 model 是谁 —— 这是端点身份的唯一硬证据
print(r.usage)          # prompt_tokens / completion_tokens

The model field echoed back is the only hard evidence of identity. A request that silently fell through to a default provider still returns HTTP 200 and still returns sensible text, which is exactly why this layer exists. If the echoed model is not the one you asked for, you are talking to someone else.

Layer 3 — did it land in the usage log?

Reachability is not billing. Open the provider's usage view and look for the model ID you just called, on today's date. If the call succeeded but does not appear, you either hit a cached response or you are still on the old path. This layer is also the one that catches the case where two environments share a key and you are reading the wrong one.

Three ways this check lies to you

FAQ

Why do I get a 401 with a key that works elsewhere?

Almost always the header. The Anthropic API authenticates with x-api-key and expects an anthropic-version header, not Authorization: Bearer. Keys are also easy to truncate when copying.

Why 404 on a path that looks correct?

A doubled version segment. If your base URL already ends in /v1, do not add it again before /messages, the request becomes /v1/v1/messages and returns 404.

What does 'max_tokens is required' mean?

Exactly that: unlike the OpenAI API, where the field is optional, this API rejects requests without it. Add max_tokens to every call.

Is a 429 the same as a 529?

No. A 429 means you hit your own rate limit and should back off; a 529 means the upstream is overloaded. Both warrant retry with backoff, but only the first is about your quota.

How do I tell whether the endpoint or my code is at fault?

Reproduce with curl from the same machine. If curl succeeds and your app fails, the problem is in your client configuration (headers, base URL or environment variables).

Related

Get API access

Rate cards: Claude and GPT