Status codes
Match on the status first, then onerror.code (also sent as the x-sideren-error-code
header) when you need the exact reason.
The error
type follows the protocol you called: invalid_request_error,
authentication_error, billing_error (402), permission_error (403),
rate_limit_error (429), and api_error or server_error for 5xx (overloaded_error for a
capacity shortage on /v1/messages).
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:
429and5xx. A402(credits used up) or403won’t clear by waiting, and any other4xxwill fail identically on every attempt; fix the request instead. - Honor
retry-afterexactly: on429and503it is the number of seconds until there is room. 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. Because the model may
already have emitted tool calls your client ran, decide in your client whether to send the
turn again. See Streaming.