Status codes
Error body shape
Every error returns a JSON body with anerror object carrying a type and a message.
On the Anthropic endpoint it is Anthropic-shaped:
Anthropic-shaped (/v1/messages)
OpenAI-shaped (/v1/chat/completions, /v1/responses, ...)
Retries and backoff
The retry recipe every production agent should ship:- Retry only what can succeed —
429with typerate_limit_errorand5xx. A 429 with typeallowance_exhaustedwon’t clear until the month resets (or you upgrade), and a4xxwill fail identically on every attempt; fix the request instead. - Honor
retry-afterexactly — on429it is the number of seconds until capacity opens. Waiting less just burns attempts. - Exponential backoff with jitter everywhere else — e.g. 1s, 2s, 4s, 8s with ±20% jitter, capped around five attempts.
- Fail loud after the cap — surface the final
error.message; it is written to be actionable.
Minimal backoff loop
The official OpenAI and Anthropic SDKs already do all of this — including honoring
retry-after — with no configuration. Hand-rolled HTTP clients are where retries usually
go missing.Streaming failures
If a stream cannot complete, it ends with a protocol-shaped error event rather than silently returning an empty response — your client always learns the turn failed. Treat a mid-stream error like a5xx: retry the whole request with backoff. See
Streaming.