Errors
Every status and error code the inference API returns, the error body, Retry-After, the order checks run in, and which errors to retry.
The error body
Errors from the inference API use OpenAI's shape:
{
"error": {
"message": "Not enough credit for this request. Add credit in the Console, or lower max_tokens.",
"type": "insufficient_quota",
"code": "insufficient_credit",
"param": null
}
}codeis the field to branch on. It is stable; themessagewording may change.typefollows the status:invalid_request_errorfor 400, 404 and 413,authentication_errorfor 401,insufficient_quotafor 402,permission_errorfor 403,rate_limit_errorfor 429, andapi_errorfor 5xx.paramnames the offending field when there is one, such asmodelormessages[0].content.- Messages are written by Safeguard. A provider's own error text is never copied into them; a provider failure is described by its HTTP status only.
- An error returned after the gateway accepted the request and called a provider also carries an
X-Generation-Idheader with the request's id (gen-…), because the request is in the request log. A refusal before that, such as a 401, 402 or 429rate_limited, has no request id.X-Request-Idis a different, internal id for Safeguard's audit trail.
The OpenAI SDKs turn these into their usual exceptions, with the status code and this body.
Every status and code
| Status | code | When | Retry? |
|---|---|---|---|
| 400 | invalid_request | The body is not valid JSON or not an object, or a field is missing or out of range, such as an unknown role, temperature above 2 or more than 2,000 messages. Also a custom: model that cannot be used. | No. Fix the request. |
| 400 | unsupported_parameter | A message part that is not text, n other than 1, or a custom: model sent with an API key. Also a routing field (models, provider.order, only, ignore, sort) where routing is not switched on, or on an embeddings request; and the completions fields that are not supported. param names the field. | No. |
| 400 | upstream_rejected | The provider refused the request: it answered 400, 404, 413 or 422. | No. Change the request. |
| 401 | invalid_api_key | The key is missing, malformed, unknown, revoked or expired, or its owner can no longer use it. | No. |
| 402 | insufficient_credit | The workspace's available credit does not cover the most this request could cost, or the balance is at or below zero. | After credit is added, or with a lower max_tokens. |
| 402 | key_spend_limit_exceeded | The request would take the key past its monthly spend limit. | After the key's limit is raised, or next month. |
| 402 | account_spend_limit_exceeded | The request would take the workspace past its monthly spend limit. | After a tenant admin or super admin raises it, or next month. |
| 403 | gateway_disabled | The API Platform is not switched on for this workspace, or the endpoint you called (embeddings, completions) is not. | No. |
| 404 | model_not_found | model is not in the catalog. | No. |
| 413 | request_too_large | The request body is larger than 8 MiB. | No. |
| 429 | rate_limited | The key reached its requests-per-minute limit. Retry-After says how many seconds to wait. | Yes, after Retry-After. |
| 429 | upstream_rate_limited | The provider is rate limiting the gateway. Retry-After is 5. | Yes, after Retry-After. |
| 500 | internal_error | The gateway failed unexpectedly. | Yes, with backoff. |
| 502 | upstream_error | The provider returned an error, could not be reached, or its stream broke. | Yes, with backoff. |
| 502 | upstream_auth | The provider refused Safeguard's own credentials. | Later. Tell Safeguard if it persists. |
| 503 | model_unavailable | The model cannot be called through the API: it has not passed the launch checks, or zero data retention was required and the model does not offer it, or the model catalog could not be read. | Only the catalog case clears by itself. |
| 503 | auth_unavailable | Safeguard could not check API keys at that moment. | Yes, after a short wait. |
| 503 | billing_unavailable | Safeguard could not check credit at that moment. The gateway refuses rather than serve a request it cannot meter. | Yes, after a short wait. |
| 504 | upstream_timeout | The provider did not answer in time, or a stream ran past 900 seconds. | Yes, with backoff. |
Two answers do not use this body, because they come from the API's router before the gateway's code runs: a path the API does not serve, such as /embeddings, returns 404 with {"detail": "Not Found"}, and a wrong method, such as GET /chat/completions, returns 405 with {"detail": "Method Not Allowed"}.
The messages you will see most
code | message |
|---|---|
invalid_api_key | Invalid, revoked or expired API key. Keys start with sg-api- and are sent as 'Authorization: Bearer <key>'. |
gateway_disabled | The Safeguard inference API is not enabled for this account. |
insufficient_credit | Not enough credit for this request. Add credit in the Console, or lower max_tokens. |
key_spend_limit_exceeded | This API key's monthly spend limit would be exceeded. |
account_spend_limit_exceeded | Your account's monthly spend limit would be exceeded. |
rate_limited | Too many requests for this API key (limit 60 per minute). The number is the key's limit. |
model_not_found | Model not found: <id> |
model_unavailable | Model <id> is not available: it is not available through the API yet. Or: zero data retention is not offered for it. |
unsupported_parameter | Only text content is supported (got 'image_url'). Or: Only n=1 is supported. |
Retry-After
Two errors carry a Retry-After header, in whole seconds:
429 rate_limited: the time until your oldest counted request leaves the 60-second window. A refused request is not counted, so a retry after that wait goes through.429 upstream_rate_limited: always5.
The order of the checks
The gateway checks a request in this order and answers with the first problem it finds:
- The key (
401), then whether the API Platform is on for the workspace (403). - The body: size (
413) and fields (400). - The key's requests per minute (
429 rate_limited). - The model: known (
404) and callable (503). - Credit and spend limits for the most the request could cost (
402). - The provider call (
400 upstream_rejected,429 upstream_rate_limited,502,504).
A request refused at steps 1 to 5 never reaches a provider and costs nothing.
Errors during a stream
Once a stream has started, the status is already 200, so a failure arrives as an event in the stream instead:
data: {"error": {"message": "The provider stream ended with an error.", "type": "api_error", "code": "upstream_error", "param": null}}It is followed by the usage chunk, if you asked for one, and data: [DONE]. See Streaming.
How to retry
- Retry
429afterRetry-After. Retry500,502,503 auth_unavailable,503 billing_unavailableand504with exponential backoff and a cap on attempts. - Do not retry the other
4xxerrors unchanged; they will fail the same way. - Each retry is a new request with a new request id. A retry that reaches a provider and gets an answer is billed like any other request.
- When your workspace or request allows fallbacks, the gateway already retries a failed provider call once before it answers with an error. See Reliability and fallbacks.
Troubleshooting walks through the common cases and their fixes.
Streaming
Server-sent events from POST /chat/completions: the chunk format, the final usage chunk, errors during a stream, and what cancelling does and does not save.
Limits
Rate limits per key, spend limits per key and per workspace, the prepaid credit hard stop, request size and time limits, and what happens when each is reached.