← Blog

Claude API Error Code Reference Guide

2026-09-24 · 5 min read · SubToAPI Team

When a Claude API call fails, the response body tells you exactly what went wrong — but the meaning of invalid_request_error versus overloaded_error versus a bare 429 isn't always obvious if you haven't memorized the spec. This guide is a practical reference: every error type you'll encounter, what triggers it, and how to handle it in code.

The short version: Claude API errors follow a consistent JSON shape with an HTTP status code and a type field nested under error. Once you know the eight or nine error types that actually occur, debugging becomes a lookup problem instead of a guessing game.

The standard error shape

Every failed request returns something like this:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "messages.0.content: Field required"
  }
}

The HTTP status code tells you the category, and error.type tells you the specifics. Always parse both — status codes alone aren't granular enough to decide retry logic.

Full error code reference

400 — invalid_request_error

The request is malformed: missing required fields, wrong types, an invalid model name, or a messages array that doesn't alternate user/assistant roles correctly. The message field usually points to the exact field. This is a client bug — retrying without fixing the payload will fail again every time.

Common causes:

401 — authentication_error

The API key is missing, malformed, or revoked. Check that the Authorization header (or x-api-key, depending on the platform you're using) is actually being sent and that the key hasn't been rotated. This is not something you retry — you need to fix credentials first.

403 — permission_error

The key is valid but doesn't have access to the requested resource — often a model tier restriction or an organization-level permission issue. Different from 401: authentication succeeded, authorization failed.

404 — not_found_error

The endpoint or resource doesn't exist. Usually a typo in the URL path, or you're hitting a resource ID (like a message or batch) that was deleted or never existed.

413 — request_too_large

The request payload exceeds size limits — typically from oversized file uploads, huge conversation histories, or large tool outputs stuffed into a single message. Trim the payload or paginate the conversation.

429 — rate_limit_error

You've exceeded requests-per-minute, tokens-per-minute, or a concurrency limit. This is retryable — back off and try again. Anthropic's official docs recommend exponential backoff with jitter; most SDKs implement this automatically. Watch for the retry-after header when present.

500 — api_error

An unexpected error on the provider's infrastructure. Rare, not your fault, and safe to retry after a short delay.

529 — overloaded_error

The API is temporarily overloaded and can't accept more traffic. This looks similar to a rate limit but is a capacity issue, not a quota issue. Retry with backoff; it usually clears within seconds to a couple of minutes.

Handling errors in code

Here's a general pattern that covers retryable vs. non-retryable errors:

async function callClaude(payload, retries = 3) {
  for (let attempt = 0; attempt <= retries; attempt++) {
    const res = await fetch("https://api.anthropic.com/v1/messages", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        "x-api-key": process.env.ANTHROPIC_API_KEY,
        "anthropic-version": "2023-06-01"
      },
      body: JSON.stringify(payload)
    });

    if (res.ok) return res.json();

    const body = await res.json();
    const type = body.error?.type;
    const retryable = [429, 500, 529].includes(res.status);

    if (!retryable || attempt === retries) {
      throw new Error(`${type}: ${body.error?.message}`);
    }

    const delay = 2 ** attempt * 500 + Math.random() * 250;
    await new Promise(r => setTimeout(r, delay));
  }
}

The key decision point is retryable: 400, 401, 403, and 404 mean something is structurally wrong with your request or credentials, and retrying identical payloads wastes time and quota. 429, 500, and 529 are transient — retry with backoff.

Error codes get more confusing with proxies

If you're calling Claude through a proxy, gateway, or wrapper service, error codes can get muddied — you might see a generic 502 from the proxy layer instead of the underlying Claude error, which makes debugging harder because you've lost the error.type detail.

This is one of the reasons SubToAPI (https://subtoapi.app) passes through the same error shape and status codes you'd get from a direct integration, rather than wrapping or obscuring them. If you're using SubToAPI to turn your Claude access into an HTTPS API with application keys (sub_live_...), streaming, and usage metadata, error handling code you write against the reference above works unchanged. The docs cover the full request/response format, and the quickstart walks through your first authenticated call if you want to see the error responses firsthand.

Practical debugging checklist

When a call fails, work through this in order:

  1. Log the full error body, not just the status code — error.type and message together tell you almost everything.
  2. Check the request payload against the messages format if you get a 400 — role alternation and required fields are the most common culprits.
  3. Verify the key is current and scoped correctly if you get a 401 or 403.
  4. Add backoff for 429 and 529 — don't hammer retries with fixed delays.
  5. If streaming, errors can arrive mid-stream as an event rather than an HTTP status — check the streaming docs for the event format.
  6. If using tools, malformed tool schemas often surface as 400 errors with a message pointing at the specific tool definition — see the tools docs for the expected structure.

questions

What does a 529 error mean for Claude API? It means the API is temporarily overloaded, not that you've hit a quota. It's retryable — use exponential backoff and the request will usually succeed within a short window.

How do I tell a rate limit error from an authentication error? Check the HTTP status: 401 means bad or missing credentials, 429 means you've exceeded a rate limit. The error.type field (authentication_error vs rate_limit_error) confirms it explicitly.

Should I retry every failed Claude API request? No. Only retry 429, 500, and 529 — these are transient. 400, 401, 403, and 404 indicate a problem with the request or credentials that retrying won't fix.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →