Error contract
Two kinds of errors
Section titled “Two kinds of errors”- Provider errors — forwarded to you as-is (status code and body unchanged). Your existing provider-specific error handling keeps working.
- Gateway errors — returned before the request reaches the provider, with a JSON envelope:
{"error": {"type": "<machine-readable>", "message": "<human-readable>"}}Gateway status codes
Section titled “Gateway status codes”| Code | Type | When | What to do |
|---|---|---|---|
401 | unauthorized | Key missing, unknown, or revoked | Check the key and the auth header for this provider |
403 | forbidden | Missing scope, or the model is not entitled to this key | Check GET /gw/me; ask your admin for access |
400 | bad_request | Malformed request the gateway must reject (e.g. async CREATE without model, invalid limit) | Fix the request |
404 | not_found | Async task does not exist or belongs to another organization; key not found on revoke | — |
429 | rate_limited | Per-key RPS or concurrency limit exceeded; Retry-After: 1 is set | Back off and retry |
402 | budget_exceeded | Organization budget exhausted (when enforcement is on) | Contact your admin |
410 | gone | Async task can no longer be finalized (upstream credentials rotated) | Re-create the job |
503 | unavailable | Transient failure finalizing an async task | Retry the poll |
502 / 504 | — | Provider unreachable / timed out (no JSON envelope) | Retry with backoff; consider SDK fallback chains |
Debugging
Section titled “Debugging”Every response carries X-Gateway-Request-Id. Quote it in support requests —
it pins down the exact request in logs and usage records.
The Python SDK maps this contract onto a typed exception
hierarchy (AuthError, RateLimitError, ProviderUnavailableError, …) and
implements automatic retries and provider fallback.