HTTP error codes
Every error from the Glexir gateway uses OpenAI's error shape, so OpenAI-compatible clients handle it without changes. This page lists every status, type and code the gateway returns, what causes it, and how to fix it.
Error shape
messagestringoptional- A readable explanation. It can change, so do not match on it.
typestringoptional- The broad error class, such as invalid_request_error or rate_limit_error.
paramstring | nulloptional- The request field that caused the error, when there is one (for example model, tools[0] or service_tier).
codestring | nulloptional- A stable machine-readable code. Branch on this. Some errors have no code.
Every response, success or error, carries an x-request-id header (req_...). Include it when you contact support.
Handle errors in code
Branch on status and code, not on message.
APIConnectionError extends APIError, so test for it first. The SDK has no class for 402 or 413; those are plain APIError instances. See Errors & retries for the full class list and retry rules.
Summary
| Status | type | code | Meaning |
|---|---|---|---|
| 400 | invalid_request_error | null, model_not_found, unsupported_on_glexir | The request is malformed or uses something Glexir does not support. |
| 401 | authentication_error | invalid_api_key | The API key is missing, wrong or revoked. |
| 402 | insufficient_quota | credit_balance_exhausted, spend_limit_exceeded | Not enough credit, or a monthly spend limit would be passed. |
| 403 | permission_error, invalid_request_error | account_suspended, model_not_priced, tier_not_allowed | Your organization, the model or the service tier is not allowed. |
| 404 | invalid_request_error | unknown_endpoint, model_not_found, null | The endpoint, model or object does not exist for you. |
| 409 | invalid_request_error | idempotency_request_in_progress, idempotency_stream_replay, cross_account_reference | An idempotency conflict, or objects that can't be combined. |
| 413 | invalid_request_error | request_too_large, file_too_large | The body or file is over the size limit. |
| 422 | invalid_request_error | idempotency_key_reused | The Idempotency-Key was used for a different request. |
| 429 | rate_limit_error | rate_limit_exceeded, concurrency_limit_exceeded, rate_limited | Too many requests, too many at once, or upstream is busy. |
| 500 | server_error | null | An unexpected error in the gateway. |
| 502 | server_error, upstream_error | upstream_unreachable, upstream_auth_failed, upstream code or null | The upstream provider failed or could not be reached. |
| 503 | service_unavailable_error, server_error | capacity_unavailable, upstream code or null | Glexir is temporarily out of upstream capacity. |
You are not charged for a request that ends in an error response. The credit reserved for it is released. Streams are the exception: see Errors during a stream.
400 Bad request
type is invalid_request_error.
code | Cause | Fix |
|---|---|---|
null | The body is not valid JSON or not a JSON object; a required field is missing (input on embeddings, metadata on an update, input_file_id on a batch); a multipart endpoint got another content type; Idempotency-Key is longer than 255 characters (param is Idempotency-Key). | Read message and param, and fix the request. |
model_not_found | model is missing; the model is not valid for this endpoint (for example an embedding model on /v1/responses); the model is not enabled for Glexir; or the model only works on /v1/responses and you called /v1/chat/completions. param is model. | Use a model from GET /v1/models that matches the endpoint. Models with -pro in the name only work on the Responses API. |
unsupported_on_glexir | The request uses a feature Glexir does not offer: an OpenAI-hosted tool (web search, file search, code interpreter, MCP, image generation, shell, computer use, apply patch, tool search), input items those tools produce, a tool_choice that targets them, audio input or output, web_search_options, or a dashboard prompt template. param points at the field. | Remove the feature. Use function or custom tools that you run yourself, send instructions in instructions, and send audio to /v1/audio/transcriptions. See Migrate from OpenAI. |
Batch input files are checked line by line when you upload them. A failing line returns 400 with param: "file", a message that starts with Batch line N:, and the code of the underlying problem (for example unsupported_on_glexir). Other upload errors: purpose must be user_data or batch, and batch files must end in .jsonl, contain at most 50,000 requests, use one model and one URL, and must not stream.
Errors that OpenAI returns for your request's content (for example an invalid parameter value) are passed through with OpenAI's status, type, code and param. Any OpenAI organization or project identifiers in the message are redacted.
401 Authentication failed
type | code | Cause | Fix |
|---|---|---|---|
authentication_error | invalid_api_key | No Authorization: Bearer header, an unknown key, or a revoked key. | Send Authorization: Bearer glx_live_... with an active key from the dashboard. |
A revoked key can keep working for up to 30 seconds while the gateway's key cache expires. Do not retry a 401; the SDK does not.
402 Payment required
Glexir is prepaid. Before a request goes upstream, the gateway reserves its worst-case cost from your balance. A 402 means that reservation was refused. type is insufficient_quota.
code | param | Cause | Fix |
|---|---|---|---|
credit_balance_exhausted | null | Your available balance (credit minus what in-flight requests have reserved) can't cover this request's reservation. The message shows both amounts. | Add credits or turn on auto-recharge on the Billing page. Set max_output_tokens (or max_completion_tokens) so the reservation is smaller. |
spend_limit_exceeded | organization | The request would push your organization past its monthly spend limit. | Raise the limit on the Limits page, or wait for the next calendar month. |
spend_limit_exceeded | api_key | The request would push this API key past its own monthly limit. | Raise the key's limit on the API keys page, or use another key. |
The reservation is an upper bound. When you set no output cap, the gateway reserves for 32,000 output tokens, so a small balance can be refused even for a short request. After the request finishes you are charged the actual usage and the rest is released. See Credits & billing.
Neither SDK retries a 402. Retrying will not help until you add credit or change the limit.
403 Forbidden
type | code | param | Cause | Fix |
|---|---|---|---|---|
permission_error | account_suspended | null | Your organization is suspended, frozen or closed. | Contact support. |
invalid_request_error | model_not_priced | model | The model has no price in Glexir's price book, so Glexir does not sell it. Dated snapshot names (for example gpt-5.4-mini-2026-03-17) are not sold; use the alias. | Use a model listed by GET /v1/models or on Pricing. |
permission_error | tier_not_allowed | service_tier | Your account tier does not allow this service_tier for this model, or the model is not sold on that tier. For example, priority needs account tier 2 or higher. | Drop service_tier or use one your tier allows. See Rate limits & spend limits. |
404 Not found
type is invalid_request_error.
code | Cause | Fix |
|---|---|---|
unknown_endpoint | The path is not served by Glexir, for example POST /v1/images/generations or POST /v1/audio/speech. The message names the method and path. | Use a supported endpoint. See What Glexir rejects. |
model_not_found | GET /v1/models/{model} for a model Glexir does not sell. | Pick a model from GET /v1/models. |
null | A response, conversation, chat completion, file or batch ID that does not exist or belongs to another organization. Both cases look the same. The message is No <object> found with id '<id>'. | Check the ID, and that you created it with a key from the same organization. Objects created directly on OpenAI do not exist on Glexir. |
409 Conflict
type is invalid_request_error.
code | Cause | Fix |
|---|---|---|
idempotency_request_in_progress | Another request with the same Idempotency-Key is still running. | Wait and retry with the same key. You will get the stored result once the first request finishes. |
idempotency_stream_replay | The original request with this key was a stream. Streams are not stored, so they can't be replayed. | Do not retry a finished stream with the same key. Send a new request with a new key if you need the output again. |
cross_account_reference | The request references stored objects (files, a previous response, a conversation) that live in different Glexir regions and can't be used together. | Use objects that were created together, or upload the file again and reference the new ID. |
The @glexir/sdk and the official OpenAI SDKs retry every 409 up to maxRetries times. That helps with idempotency_request_in_progress but not with the other two codes.
413 Payload too large
type is invalid_request_error.
code | param | Cause | Fix |
|---|---|---|---|
request_too_large | null | A JSON body is over 20 MB, for example because of large base64 images or PDFs. | Upload large files with purpose: "user_data" and reference them by file_id. |
file_too_large | file | An audio file is over 25 MB, a user_data file is over 50 MB, or a batch file is over 20 MB. | Split audio into chunks. Split batch input across several files. |
422 Unprocessable entity
type | code | Cause | Fix |
|---|---|---|---|
invalid_request_error | idempotency_key_reused | You sent an Idempotency-Key that was used in the last 24 hours with a different method, path or body. | Use a new key for every distinct request. |
429 Too many requests
type is rate_limit_error.
code | Cause | Fix |
|---|---|---|
rate_limit_exceeded | Your organization sent more requests in the current minute than its account tier allows. The response has a retry-after header in seconds. | Wait retry-after seconds. Both SDKs do this automatically. Spread requests out, or move bulk work to batches. |
concurrency_limit_exceeded | Your organization already has the maximum number of requests in flight for its tier. The message shows the limit. | Limit parallelism in your client, for example with a queue. |
rate_limited | Upstream capacity is busy after the gateway's own retries. | Retry with backoff. |
The requests-per-minute limit counts every authenticated request, including ones that later fail. Limits are per organization, not per key. See Rate limits & spend limits.
5xx Server and upstream errors
| Status | type | code | Cause |
|---|---|---|---|
| 500 | server_error | null | An unexpected error in the gateway. |
| 502 | server_error | upstream_unreachable | No upstream connection could be made. |
| 502 | upstream_error | upstream_auth_failed | The upstream provider rejected Glexir's credentials. This is Glexir's problem, not your key. |
| 502 | server_error | upstream code or null | The upstream provider returned a 5xx other than 503. |
| 503 | service_unavailable_error | capacity_unavailable | Glexir is temporarily out of upstream capacity. |
| 503 | server_error | upstream code or null | The upstream provider returned 503. |
All of these are safe to retry with backoff, and both SDKs retry them by default. If they persist, contact support with the x-request-id.
Upstream retries and failover
The gateway retries upstream failures (408, 429 and 5xx responses, and connection errors) before it returns an error to you:
- Stateless requests can be served by another upstream route. These are Chat Completions requests that don't reference stored files, embeddings, transcriptions and translations, model lookups, and input token counts.
- Requests tied to stored state stay on the route that holds that state and get one more attempt there. This covers every
POST /v1/responses(responses carry encrypted reasoning bound to where they were created), anything that usesprevious_response_id, a conversation or a stored file, and every file, batch and conversation endpoint.
On a retry to the same route, if the upstream asks for a delay longer than 10 seconds, the gateway does not wait. It returns the error so your client can decide.
Errors during a stream
Once a stream has started, the HTTP status is already 200. An error then arrives as an SSE error event in the same shape:
code | Cause |
|---|---|
stream_timeout | The upstream stream sent nothing for the idle timeout (10 minutes by default) and was closed. |
upstream_stream_error | The upstream connection failed mid-stream. |
Error events from the upstream stream itself are passed through unchanged. In @glexir/sdk, a mid-stream error is thrown as an APIError whose status is undefined, so check err.code. Neither SDK retries a stream after it has started.
Billing for a text stream that ends early: if the upstream reported usage, you pay that usage. If the stream ended without a usage report, you are charged an estimate of the input tokens only. A transcription stream without a usage report is charged by the audio's duration.
SDK error classes
@glexir/sdk maps statuses to classes. All extend APIError, which extends GlexirError.
| Class | When |
|---|---|
BadRequestError | 400 |
AuthenticationError | 401 |
PermissionDeniedError | 403 |
NotFoundError | 404 |
ConflictError | 409 |
UnprocessableEntityError | 422 |
RateLimitError | 429 |
InternalServerError | Any status of 500 or more |
APIError | Any other status, including 402 and 413, and errors inside a stream (status is undefined) |
APIConnectionError | No response: network failure. status is undefined. |
APIConnectionTimeoutError | No response within timeout. Extends APIConnectionError. |
APIUserAbortError | You aborted the request with signal. |
Two errors do not come from the API. parse() throws LengthFinishReasonError when the output hit the token limit and ContentFilterFinishReasonError when the content filter cut it off. Both extend GlexirError.
statusnumber | undefinedoptional- HTTP status. undefined for connection errors, aborts and errors inside a stream.
codestring | null | undefinedoptional- error.code from the body.
typestring | undefinedoptional- error.type from the body.
paramstring | null | undefinedoptional- error.param from the body.
errorAPIErrorBody | undefinedoptional- The whole error object: message, type, code, param and any other fields.
headersHeaders | undefinedoptional- Response headers, for example retry-after.
requestIDstring | null | undefinedoptional- The x-request-id header. Quote it to support.
messagestringoptional- The status followed by error.message, for example "402 Your Glexir credit balance is too low ...".