Errors come back in an envelope your SDK already understands, so its error handling works unchanged. The message field carries the specific reason; the status tells you whether retrying is worth anything.
{
"error": {
"message": "insufficient user quota (request id: 20261023134440506372632uNByXKMX)",
"type": "clawrouter_error",
"code": "insufficient_user_quota"
}
}- type clawrouter_error means the gateway refused the request itself: the key, the balance, or a model you cannot call. These use the first shape on every endpoint.
- When the model provider rejects a request, the error takes the shape of the API you called. The OpenAI shape carries invalid_request_error, rate_limit_error or server_error; on /v1/messages it is Anthropic's own type, such as invalid_request_error, rate_limit_error or overloaded_error.
Status codes
| Status | Meaning | What to do |
|---|---|---|
401 | Key missing, malformed, revoked or expired | Check the Authorization header, then reissue the key |
403 | Key is valid but not allowed this model, or quota is exhausted | Check the key's model allowlist and the account balance |
404 | The model does not exist or your key cannot use it (code model_not_found) | Call GET /v1/models for names this instance actually serves |
429 | A rate limit was exceeded, ours or the provider's | Wait for the Retry-After header (seconds), then retry with jitter |
503 | The model exists but every route to it is down right now (code model_unavailable) | Retry with backoff |
5xx | Upstream provider failed or timed out | Retry; failover to another channel is automatic where one exists |
Retrying
Retry 429 and 5xx with exponential backoff and jitter. Do not retry 401 or 403 — they are decisions about your key, not transient conditions, and hammering them will not change the answer.
Every response carries an X-Request-Id header, and error messages end with the same id. Quote it when you report a problem; it is how a request is found in our logs.
