LLM Gatewaydocs

Errors

All errors — from the gateway's /v1 API and from the dashboard API — use one JSON envelope and one set of codes. Use error.code for programmatic handling; error.type groups codes into broad classes; error.message is for humans and may change.

The envelope

json
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "Rate limit exceeded for api_key (60 requests/minute)",
    "request_id": "req_01J6ZK3M9PQR7S8T9V",
    "param": null,
    "provider": null,
    "retry_after": 2,
    "details": null
  }
}
FieldTypeAlwaysDescription
typestringyesOne of invalid_request_error, authentication_error, permission_error, rate_limit_error, quota_error, not_found_error, conflict_error, provider_error, timeout_error, internal_error.
codestringyesMachine-readable code from the table below. Stable.
messagestringyesHuman-readable explanation. Not stable; do not parse.
request_idstringyesSame value as the X-Request-Id header. Quote it in support requests.
paramstringnoJSON path of the offending request field for validation errors (e.g. messages.0.content).
providerstringnoSlug of the upstream provider involved in a provider error. Never contains credentials.
retry_afterintegernoSeconds to wait before retrying; mirrors the Retry-After header.
detailsanynoOptional structured context (e.g. a list of validation issues).

Errors on /v1 are compatible with OpenAI SDK error handling: the SDKs read error.message, error.type, error.code and error.param and raise the class matching the HTTP status (AuthenticationError, RateLimitError, BadRequestError, …).

Streaming errors

Once an SSE stream has started (HTTP 200 already sent), an error is delivered as a data event containing the same envelope, followed by [DONE]:

text
data: {"error":{"type":"provider_error","code":"stream_interrupted","message":"provider connection lost","request_id":"req_…","provider":"groq"}}

data: [DONE]

See Streaming.

Retry-After

Every 429 response and every 409 idempotency_conflict caused by an in-flight duplicate carry a Retry-After header (seconds, integer) and the matching error.retry_after. 503/504 provider failures may also include it when the upstream supplied one. Honour it before retrying.

Status codes

HTTPtypeTypical codes
400invalid_request_errorinvalid_json, validation_failed, idempotency_key_required, ssrf_blocked
401authentication_errorinvalid_api_key, key_expired, key_disabled, key_revoked
402quota_errorinsufficient_credits, budget_exceeded, spending_limit_exceeded
403permission_errorip_not_allowed, model_not_allowed, modality_not_allowed
404not_found_errormodel_not_found, not_found
409conflict_erroridempotency_conflict, job_not_cancellable
413invalid_request_errorrequest_too_large
415invalid_request_errorunsupported_media_type
429rate_limit_errorrate_limited, tokens_per_minute_exceeded, concurrency_exceeded, provider_rate_limited
500internal_errorinternal_error
501invalid_request_errornot_implemented, not_configured
502provider_errorprovider_error, provider_disconnect, stream_interrupted
503provider_error / internal_errorno_provider_available, provider_unavailable, service_unavailable
504timeout_errorprovider_timeout

Every error code

This table is generated at build time from the platform's shared schema package, so it is always complete. Codes marked (dashboard API only) are emitted by the control-plane API used by the dashboard and never by /v1.

HTTPcodetypeMeaningRetry?
400idempotency_key_requiredinvalid_request_errorVideo and music generation require an Idempotency-Key header.No — add the header
400invalid_jsoninvalid_request_errorThe body is not valid JSON.No — fix the request
400ssrf_blockedinvalid_request_errorA URL you supplied (input image, webhook) points at a private, loopback or otherwise blocked address.No — use a public https URL
400validation_failedinvalid_request_errorThe body is valid JSON but violates the schema; param points at the offending field.No — fix the request
401invalid_api_keyauthentication_errorThe Authorization header is missing, malformed, or the key does not exist.No — fix the key
401invalid_credentialsauthentication_errorWrong email or password.(dashboard API only)No
401key_disabledauthentication_errorThe key was disabled in the dashboard.No — re-enable in the dashboard
401key_expiredauthentication_errorThe key’s expires_at has passed.No — rotate or create a new key
401key_revokedauthentication_errorThe key was revoked (or replaced by rotation).No — use the new key
401unauthenticatedauthentication_errorNo valid session cookie.(dashboard API only)No — sign in
402budget_exceededquota_errorThe key’s daily or monthly budget would be exceeded.No — raise budget or wait for the window
402insufficient_creditsquota_errorThe organization balance cannot cover the estimated cost.No — top up credits
402spending_limit_exceededquota_errorThe organization’s monthly spending limit would be exceeded.No — raise the limit
403account_disabledpermission_errorThe user account is disabled.(dashboard API only)No
403csrf_failedpermission_errorMissing X-Requested-With header on a mutating dashboard request.(dashboard API only)No
403email_not_verifiedpermission_errorThe account email has not been verified.(dashboard API only)No — verify email
403forbiddenpermission_errorThe caller lacks the role required for this action.(dashboard API only)No
403ip_not_allowedpermission_errorThe caller IP is not in the key’s allowed_ips list (or the organization is not active).No — update allowed_ips
403modality_not_allowedpermission_errorThe key’s allowed_modalities scope excludes this modality.No — adjust key scope
403model_not_allowedpermission_errorThe key’s allowed_models scope excludes this model.No — adjust key scope
404model_not_foundnot_found_errorNo enabled model with this id. Check GET /v1/models.No
404not_foundnot_found_errorThe resource (job, model detail, …) does not exist or belongs to another organization.No
409conflictconflict_errorThe operation conflicts with current state.(dashboard API only)No
409idempotency_conflictconflict_errorIdempotency-Key was reused with a different request body, or the original request is still in flight (retry_after set).Only when retry_after is present
409job_not_cancellableconflict_errorDELETE on a job that is not in a cancellable state.No
409max_api_keys_reachedconflict_errorThe organization already has the maximum number of API keys.(dashboard API only)No
413request_too_largeinvalid_request_errorBody exceeds MAX_REQUEST_BYTES (default 10 MiB JSON, 25 MiB multipart).No — reduce payload
415unsupported_media_typeinvalid_request_errorContent-Type is not accepted by this endpoint (e.g. JSON where multipart is required).No
429concurrency_exceededrate_limit_errorToo many in-flight requests for this key.Yes — when a request completes
429provider_rate_limitedrate_limit_errorUpstream providers returned 429 and fallbacks are exhausted.Yes — after Retry-After
429rate_limitedrate_limit_errorRequests-per-second or requests-per-minute limit exceeded (key, org, model or global scope).Yes — after Retry-After
429tokens_per_minute_exceededrate_limit_errorEstimated tokens for this minute exceed the key’s tokens_per_minute.Yes — after Retry-After
500internal_errorinternal_errorUnexpected failure. Include request_id when contacting support.Yes — once, with backoff
501not_configuredinvalid_request_errorThe feature requires configuration the operator has not provided (e.g. object storage).No
501not_implementedinvalid_request_errorThe feature (e.g. the smart strategy, real video providers) is not implemented in this build.No
502provider_disconnectprovider_errorThe provider closed the stream before sending finish_reason.Yes — re-issue the request
502provider_errorprovider_errorThe provider returned an error the gateway could not recover from.Maybe — inspect message
502stream_interruptedprovider_errorA provider failure occurred after the first token was sent; delivered as an in-stream error chunk.Yes — re-issue the request
503no_provider_availableprovider_errorRouting found no eligible, healthy provider for the model (all disabled, open-circuit, or excluded).Yes — with backoff
503provider_unavailableprovider_errorEvery attempted provider returned 5xx/connection errors and fallbacks are exhausted.Yes — with backoff
503service_unavailableinternal_errorA dependency (Redis, database) is unavailable; the gateway fails closed.Yes — with backoff
504provider_timeouttimeout_errorThe provider did not respond within the timeout and fallbacks are exhausted.Yes — with backoff

Handling errors

typescript
import OpenAI, { APIError } from 'openai';

try {
  await client.chat.completions.create({ model: 'openai/gpt-4o-mini', messages });
} catch (err) {
  if (err instanceof APIError) {
    const code = (err.error as { code?: string } | undefined)?.code;
    switch (code) {
      case 'rate_limited':
      case 'provider_rate_limited':
        // wait err.headers['retry-after'] seconds, then retry
        break;
      case 'insufficient_credits':
      case 'budget_exceeded':
        // alert billing owner; do not retry
        break;
      case 'model_not_allowed':
      case 'model_not_found':
        // configuration problem
        break;
      default:
        console.error(err.status, code, err.requestID ?? err.headers?.['x-request-id']);
    }
  } else throw err;
}