Errors
Status codes, the error body, and which failures are worth retrying.
Errors come back as JSON with the status code that matches:
{
"error": {
"type": "insufficient_credit",
"message": "The organization's balance cannot cover this request."
}
}
Status codes
| Code | Type | Retry? |
|---|---|---|
| 400 | invalid_request |
No — fix the body |
| 401 | invalid_api_key |
No — the key is wrong or revoked |
| 402 | insufficient_credit |
After topping up |
| 404 | model_not_found |
No — check the catalogue |
| 408 | timeout |
Yes, with backoff |
| 429 | rate_limited |
Yes, honour Retry-After |
| 5xx | upstream_error |
Yes, with backoff |
What is charged
A request that fails before the provider generated anything costs nothing.
A request that fails partway — a stream that dropped, a timeout after the first
tokens — is charged for what was generated, because the provider generated it.
Those rows appear in Usage with a non-ok status and a real cost.
Retrying
Exponential backoff with jitter, and a ceiling. Retrying a 429 immediately is how a rate limit becomes an outage.
Do not retry a 400 or a 401. Neither will succeed the second time, and both usually mean a deploy shipped something wrong.
402 is a runway problem, not a request problem. If you are seeing it, auto-reload is the fix rather than a retry loop.