Claude Certification Guides
CCAR-F/Domain 59 min read

Lesson 5.5

Errors, Rate Limits, Retries and Timeouts

The error classes the API returns, how rate limits are measured and reported, and how to build clients that recover rather than fail.

Production reliability is mostly about what happens when a request does not succeed. The API reports failures with conventional HTTP status codes and typed error bodies; the SDKs translate them into exception classes and retry some automatically. The architect's job is to know which failures are retryable, how to pace requests against rate limits, and how to bound the time a request may take. The exam tests the error table, the rate-limit model and the retry discipline.

The error table

StatusTypeRetry?Meaning
400invalid_request_errorNoMalformed request: bad parameter, schema, message ordering
401authentication_errorNoMissing or invalid API key
403permission_errorNoThe key is not allowed to do this
404not_found_errorNoUnknown resource, typically a model name
413request_too_largeNoRequest body exceeds the size limit
429rate_limit_errorYes, after a delayA rate limit was exceeded
500api_errorYesInternal error on Anthropic's side
529overloaded_errorYes, with backoffThe service is temporarily overloaded

Every response carries a request-id header; log it on every call, because it is what Anthropic support needs to investigate. A 4xx other than 429 means your request is wrong, and retrying it unchanged will fail identically; fix the request. Note that a model refusal is not an error: it arrives as a 200 with stop_reason: "refusal".

Common 400 causes worth recognising: a conversation that does not begin with a user message, a tool_result without a matching tool_use, budget_tokens not below max_tokens on models that use it, and parameters a particular model does not support (sampling values, forced tool choice, prefill).

Rate limits

Limits are set per organisation and per model along three dimensions: requests per minute (RPM), input tokens per minute (ITPM) and output tokens per minute (OTPM). They scale with usage tier, which rises with spend over time, and can be raised on request. Each response reports the current state in headers: anthropic-ratelimit-requests-limit, -remaining and -reset, with parallel sets for input and output tokens, plus retry-after on a 429 telling you how long to wait. Some models exclude cached input tokens from the ITPM count, which makes caching a rate-limit tool as well as a cost tool; check the rate limits page for specifics.

Design implications: read the headers and slow down before hitting zero rather than after; spread bursty workloads over time; and route genuinely non-urgent work to the Message Batches API, which runs asynchronously within a day at a lower price and under separate limits.

Retries

The SDKs retry automatically, twice by default, with exponential backoff and jitter, on connection errors, 408, 409, 429 and 5xx responses. You can raise max_retries on the client or per request. For your own retry logic the rules are:

  • Retry only retryable classes (429, 500, 529, network errors).
  • Honour retry-after when present.
  • Back off exponentially with jitter so that many clients do not retry in lockstep.
  • Cap total attempts and total elapsed time.
  • Make the operation idempotent before retrying it, since a request that timed out may have completed.
from anthropic import RateLimitError, APIStatusError, APIConnectionError

try:
    response = client.messages.create(**params)
except RateLimitError as e:
    schedule_retry(after=float(e.response.headers.get("retry-after", "5")))
except APIStatusError as e:
    if e.status_code >= 500: schedule_retry(backoff=True)
    else: raise                      # 4xx: fix the request
except APIConnectionError:
    schedule_retry(backoff=True)

Catch specific exceptions first; a single broad handler loses the distinction between "wait" and "fix".

Timeouts

The SDK default request timeout is ten minutes; units differ between SDKs (seconds in Python, milliseconds in TypeScript). Long generations should stream: streaming returns tokens as they are produced, so no single HTTP read waits for the whole response, and the SDKs require streaming for requests whose expected duration is very long. Use the stream helpers (get_final_message() / finalMessage()) when you only want the end result. Remember that retries multiply wall-clock time: a ten-minute timeout with two retries can take thirty minutes to fail.

Degrading gracefully

For user-facing systems, add a circuit breaker that stops sending to a failing route after repeated 5xx or 529 responses and recovers gradually, a fallback model for capacity incidents (Claude Code exposes --fallback-model), and clear user messaging distinguishing "try again shortly" from "this request cannot be served". Surface stop_reason values such as max_tokens and refusal as distinct outcomes rather than folding them into generic errors.

Exam focus

  • 4xx other than 429 means fix the request; 429, 500 and 529 are retryable with backoff; refusals are 200 responses, not errors.
  • Rate limits are RPM, ITPM and OTPM per model, reported in anthropic-ratelimit-* headers, with retry-after on 429.
  • SDKs retry twice by default with exponential backoff on connection errors, 408, 409, 429 and 5xx; tune with max_retries.
  • Log the request-id header on every call for support and tracing.
  • Default timeout is ten minutes; long outputs must stream; retries multiply total wall-clock time.
  • Batches, caching and header-driven pacing are the tools for staying under limits; circuit breakers and fallback models handle incidents.

Check yourself

5 questions

  1. 1.Which HTTP responses from the Claude API are appropriate to retry with exponential backoff?

  2. 2.A service starts receiving 429 responses during a traffic spike. Which handling is correct?

  3. 3.What does an HTTP 529 response signify, and how should an application respond?

  4. 4.After a 500 error, an agent harness retried the entire turn, and a customer order was created twice. What is the diagnosis and remedy?

  5. 5.What is the default retry behaviour of the official Anthropic SDKs?