SDKs & Developer Experience

Error Handling Patterns Across SDK Languages

The status codes mean the same thing in every language; what differs is how each SDK surfaces them — exceptions, rejected promises, or error values. Handle the meaning, not the mechanism.

Claude 3P 101 · Updated July 2026 · Unofficial guide

A Claude integration fails in a small number of well-defined ways, and the same failure looks different in Python than in Go. The productive way to think about error handling is in two layers: first learn what each HTTP status actually indicates (that knowledge transfers across all seven SDKs and every platform), then map it onto your language's idiom. The official SDKs expose typed errors that carry the status code and the API's error body — the exact class or type names vary per language, so check the repository README for your SDK's error hierarchy rather than guessing from another language's.

Status code semantics that matter in practice

StatusWhat it usually meansSensible reaction
400Invalid request — malformed body, or a parameter this model rejectsFix the request; never retry as-is
401 / 403Credential missing, wrong, or lacking permission/scopeCheck credential source and scoping, not your prompt
404Wrong route — or a retired model IDVerify endpoint and model against the models list
429Rate limit exceeded for your usage tierBack off with jitter, bound concurrency
5xx / overloadedTransient server-side troubleRetry with exponential backoff

Two of these deserve enterprise-specific elaboration. 400s are frequently model-migration artifacts, not bugs: newer models reject parameters older ones accepted — manual extended thinking, non-default temperature/top_p/top_k, and assistant prefill all return 400 on Sonnet 5 and recent Opus models, and input exceeding the context window returns a 400 invalid_request_error ("prompt is too long"). 403s are platform-flavored: on the first-party API a 403 can mean your Workload Identity Federation token lacks the OAuth scope for that endpoint; on Claude Platform on AWS a 403 means the request reached the server but the workspace ID is wrong or the IAM principal is missing an action. And on that platform, a SigV4 region mismatch produces a generic signature-rejection error rather than a specific diagnostic — worth knowing before you burn an afternoon on it.

Language idioms

Python raises exceptions: wrap client.messages.create(...) in try/except, catch the SDK's error types (narrow ones for statuses you handle specially, the base type as a backstop), and let truly unexpected exceptions propagate. TypeScript rejects promises: try/await/catch, or .catch() per promise when fanning out with Promise.allSettled so one failure doesn't sink a batch. Go returns error values from client.Messages.New(ctx, ...) — check them immediately, use errors.As-style unwrapping to reach the typed API error, and remember that a cancelled context surfaces as an error too. Java and C# throw; catch the SDK's exception types around client.messages().create(params) / await client.Messages.Create(parameters) and translate them at your service boundary into your application's error model.

Don't hand-roll what code can do: classify errors into exactly three buckets — retryable (429, 5xx), fix-the-request (400, 404), and fix-the-credentials (401, 403) — and write that classification once as a small function per codebase. Every call site then handles three cases instead of re-deriving status semantics.

Errors that arrive as successful responses

Two failure modes return HTTP 200 and bite teams that only check status codes. First, safety refusals: on recent models a refused request completes with stop_reason: "refusal" and a stop_details.category field (categories include "cyber" and "bio") — your code should branch on stop_reason, not just parse the text. Second, context overflow mid-generation: on Claude 4.5+ models, a request whose input plus max_tokens exceeds the window is accepted and stops with stop_reason: "model_context_window_exceeded", giving you a truncated-by-design response. Treat stop_reason as part of your error handling surface, in every language.

Where to go next

Pair this with configuring retries in the SDK and handling 429 rate-limit errors; if you run concurrent workloads, async and concurrent SDK calls shows why bounded fan-out prevents most 429s in the first place.

Sources