Errors
Every error is JSON with a stable code and a human-readable message.
Program against code, never against message text.
{
"code": "LIMIT_EXCEEDED",
"message": "rate limit exceeded, retry after 30s"
}
Common codes
| HTTP | Code | What it means | What to do |
|---|---|---|---|
| 400 | BAD_REQUEST | Malformed body or invalid parameter. | Fix the request; the message names the field. |
| 401 | UNAUTHORIZED | Missing/invalid/rotated API key. | Check the Authorization: Bearer sk-… header. |
| 402 | INSUFFICIENT_BALANCE | Wallet can't cover the call. | Top up in the console, or enable postpay. |
| 403 | FORBIDDEN | Key lacks access to this project/model. | Check project scoping and model allowlists. |
| 404 | NOT_FOUND | Unknown model or resource id. | Verify against the model catalog. |
| 409 | CONFLICT | State race (e.g. concurrent update). | Re-read then retry with fresh state. |
| 429 | LIMIT_EXCEEDED | Rate or quota limit hit. | Back off; honor Retry-After when present. |
| 5xx | INTERNAL / UPSTREAM_ERROR | Gateway or provider fault. | Retry with exponential backoff; failover is automatic. |
Retry guidance
- Idempotent reads: retry freely with backoff.
- Generation calls: retries can double-bill you on success-after-timeout; prefer short timeouts plus a single retry.
- 429: always respect
Retry-After— hammering extends the window.