Skip to content
Docs navigation: Open models / Open-model errors

Open-model errors

Open modelsOpen-model errors Updated

On this page

Most /v1 routes return the chat-style error envelope below. /v1/messages and /v1/messages/count_tokens return the Messages error envelope instead.

ConnectionValue
API basehttps://api.runinfra.ai/v1
Workspace keyrp_...
Process variableRUNINFRA_GATEWAY_KEY
BillingThe existing funding rules of your open-model account.

Replace MODEL_ID with an available id from Open models; read current capabilities, limits and prices from GET /v1/models.

JSON
JSON
{
  "error": {
    "message": "Invalid API key",
    "type": "authentication_error",
    "param": null,
    "code": "invalid_api_key"
  },
  "request_id": "req_example_0000"
}

type is the broad family, code is the specific reason, and param names the request field when one caused it. Branch on type and code, never on message text. Some errors add fields directly inside error, such as paused_until, limit, or credit amounts, never nested under a details property.

For a 401, the wire code is invalid_api_key. Clients may still tolerate auth_error as a legacy spelling for that status.

On chat-compatible routes, type is one of exactly six values.

error.typeStatuses that use it
invalid_request_error400, 405, 409, 413, 422
authentication_error400, 401, 403
permission_error402, 403
not_found_error404
rate_limit_error429
api_error500, 502, 503, 504

Failures inside the gateway return the route's documented envelope, including a failure we did not anticipate. On chat-compatible routes, that arrives as 500 internal_error rather than an empty body. The platform edge can answer before the gateway with no JSON envelope: see Payload too large and HTML 403 security checkpoint.

Chat-compatible error responses carry X-Request-Id, matching request_id. Messages-compatible responses carry both request-id and x-request-id. Quote a request id when you contact support.

On a streaming response, HTTP 200 means the stream opened. It does not prove completion: an error frame or a connection closing without the protocol's terminal event is an incomplete response. Preserve the request id and reuse the same Idempotency-Key to read the original request's receipt without a second charge. Do not include authorization headers or request content in an error report.

Should I retry?

The absence of the retry headers is a deliberate signal, not an oversight. A JSON 400, 401, 402, 403, 404 or 413 needs a different request or different credentials, so none carries timing. An HTML 403 needs a pause before retrying.

Key creation and rotation errors (api_key_rotation_overlap_limit, api_key_mint_busy) are on Rotate, revoke, expire.

Status and code reference

Statuserror.typeerror.codeWhat you should do
400invalid_request_errorinvalid_jsonSend valid JSON.
400invalid_request_errorinvalid_requestFix the field named by param.
400invalid_request_errormissing_required_fieldAdd the field named by param.
400invalid_request_errorgeneration_countReduce n, best_of, or another candidate-count field to four or fewer.
400invalid_request_errorcontext_length_exceededThe prompt is longer than the model's context window, and retrying it unchanged fails again. Compact the conversation or send a shorter prompt. error.context_window carries the window. On /v1/messages the same refusal reads prompt is too long; a streaming /v1/responses request receives it as a response.failed event. Nothing is charged.
400invalid_request_errorunsupported_model_operationUse an endpoint the selected model supports.
400invalid_request_errorhosted_capability_not_supportedDrop the capability named by param, or call a model whose page lists it.
400invalid_request_errorhosted_parameter_not_supportedFix or remove the field named by param. For response_format, send the reasoning_effort named in the message (none on most affected models, low on another), or drop the format. The model-specific source reference identifies the cases.
400invalid_request_errorinvalid_image_urlThe image named in the message failed the gateway's remote-image checks or memory bounds. Use a public PNG, JPEG, WebP or non-animated GIF within the image limits: 20 MiB transferred and decoded per remote image, 50 MiB of expanded image data URLs and a 54 MiB body when remote images are present. An inline data URL also works. param is messages; no Retry-After is sent and x-should-retry is false.
400invalid_request_errorhosted_request_unprocessableparam is messages. The model could not prepare this conversation within its time limit, or this exact request failed that way in the last 15 minutes and is not sent again yet. Compact or shorten the conversation, then retry. Very long runs of tool results in one turn are the usual cause. Retrying it unchanged does not help.
400invalid_request_errorupstream_errorThe model's server refused the request's content, for example a message or parameter shape it cannot serve. Retrying it unchanged fails the same way: fix the field named by param when present, otherwise simplify the request. Nothing is charged.
400invalid_request_errorinvalid_idempotency_keySend a non-blank printable ASCII Idempotency-Key of 255 characters or fewer.
400invalid_request_erroridempotency_mismatchThis key was already used with a different method, route, or body. Use a new key for a new request.
400invalid_request_errorinvalid_trace_headerFix or remove the header named by param. X-Client-Request-Id must be non-blank printable ASCII of 512 characters or fewer.
400authentication_errorauth_errorUse a workspace key with https://api.runinfra.ai/v1.
401authentication_errorinvalid_api_keySend an active workspace API key in the Bearer header.
402permission_errorinsufficient_creditsAdd enough credits for the reservation, then retry.
402permission_erroraccount_frozenResolve the billing issue on the workspace, or add credits, then retry. Credits do not lift a hold for a payment dispute: contact support.
402permission_errorplan_limit_reachedThe plan is at a limit and neither credits nor Standby can serve the request. Follow fixes or wait for the stated reset or refill.
402permission_errorspend_limit_reachedThis key reached the monthly spending limit its owner set. Raise or remove the limit under Settings, API keys, or wait for resets_at.
403authentication_errorauth_errorReplace a terminal, internal, or deactivated key with an active workspace API key.
403permission_errorcredits_scope_violationThe key is scoped to one deployment or endpoint, and GET /v1/credits describes the whole workspace. Use a workspace key.
403permission_errorusage_scope_violationThe key is scoped to one deployment or endpoint, and GET /v1/usage describes the whole workspace. Use a workspace key.
404not_found_errormodel_not_foundCall GET /v1/models and use an id returned for the same key.
404not_found_errorunknown_endpointThe path is not a gateway endpoint, usually a base_url that already ends in the endpoint path or a doubled /v1. The message names the exact base_url to set: chat API clients use https://api.runinfra.ai/v1, Messages protocol clients use the bare host because the SDK appends /v1/messages itself. chat API-dialect responses also carry error.base_url with the value https://api.runinfra.ai/v1.
405invalid_request_errormethod_not_allowedThe route does not serve this HTTP method. Read the Allow header and send one of the methods it lists.
409invalid_request_erroridempotency_conflictWait for Retry-After, then retry with the same key and body.
413invalid_request_errorpayload_too_largeReduce the JSON request body below 32MB. It counts the whole request, including any conversation you resend, and an image is about a third larger once base64 encoded.
422invalid_request_erroridempotency_replay_unavailableDo not switch to a new idempotency key. Contact support with the request id.
429rate_limit_errorrate_limit_exceededWait for Retry-After. The per-key window and the connection gate both send this code.
429rate_limit_errorhosted_per_key_concurrency_limitWait for Retry-After. It clears when a request using this key finishes.
429rate_limit_errorhosted_workspace_concurrency_limitWait for Retry-After. It clears when a hosted request in the workspace finishes.
429rate_limit_errorhosted_shared_model_concurrency_limitWait for Retry-After. Contact support if saturation continues.
429rate_limit_errorhosted_plan_concurrency_limitWait for Retry-After. It clears when a plan-funded request in the workspace finishes.
429rate_limit_errorhosted_standby_workspace_limitWait for Retry-After. It clears when a Standby request in the workspace finishes.
429rate_limit_errorhosted_standby_aggregate_limitWait for Retry-After. It clears when a Standby slot on this model becomes available.
429rate_limit_errorhosted_standby_pressureWait for Retry-After. It clears when load on the model drops.
429rate_limit_errorplan_window_busyYour running requests hold the rest of a coding plan limit. The server already waited up to 30 seconds. Retry after Retry-After; it clears when one of them finishes.
429rate_limit_errorhosted_workspace_tpm_limitWait for Retry-After. When one request alone exceeds the limit, waiting cannot help, so reduce its token reservation.
429rate_limit_errorhosted_admission_congestedWait for Retry-After. The gateway shed the request under momentary load. It is not a quota. The wait is randomized between 1 and 4 seconds, up to 8 under heavy load, so refused clients do not return together.
429rate_limit_errorhosted_saturated_large_promptThe model is near its concurrency limit and very large prompts are deferred first. Wait for Retry-After and retry unchanged.
429rate_limit_errorhosted_model_at_capacityEvery replica the request reached (at most two) is at capacity for the moment. Wait for Retry-After and retry unchanged; the same request succeeds once a slot frees. It is not a limit on your workspace, it carries no limit field and no X-Hosted-Limit-Scope header, and nothing is charged. See the model at capacity.
500api_errorinternal_errorRetry after Retry-After. Include X-Request-Id in a ticket if it persists.
500api_errorcredit_reservation_failedThe credit reservation could not be recorded. Retry after Retry-After.
502api_errorresponse_format_errorRetry the request. Contact support if it continues.
502api_errorupstream_errorThe model failed while serving the request, after it was admitted. Retry after Retry-After when present; otherwise back off briefly.
502api_errorupstream_http_errorThe model answered the request with an HTTP failure. Retry after Retry-After when present; otherwise back off briefly.
504api_errorhosted_inference_response_timeoutThe response exceeded its deadline, and no Retry-After is sent. For a non-streaming request, set stream: true or lower max_tokens before retrying.
200api_errorupstream_stream_errorThe stream ended early, on the same HTTP 200: its last frame carries this code, or upstream_error or hosted_inference_response_timeout when the gateway knows why, and no [DONE] follows. Treat a missing [DONE] as incomplete and retry. See Streaming.

On some models, when three prompts of about 400,000 tokens or more already run on a server, one more waits up to 30 seconds before 429 hosted_saturated_large_prompt. The model-specific error reference identifies the affected models. Use that refusal to identify the condition; wait for Retry-After and retry unchanged.

The 503 codes

A 503 means the gateway could not safely serve the request. During a rate-limit store outage, each server applies rate limits on its own instead of returning limiter_unavailable, but hosted admission and Idempotency-Key checks can still return a retryable 503. All of them carry Retry-After except upstream_http_error, which forwards one only when the model supplied it, and hosted_inference_unavailable, which carries none. For datastore_unavailable, hosted_evidence_unavailable, hosted_admission_unavailable and the connection gate's limiter_unavailable, the wait is randomized between 1 and 4 seconds, up to 8 under heavy load.

error.codeWhat happened
hosted_model_pausedThe model is temporarily paused. error.paused_until carries the next availability check. Retry-After is the time until that check, capped at one hour, and 60 seconds once the check time has passed.
limiter_unavailableThe rate-limit store is not configured, or the connection gate could not evaluate the request, so it was refused rather than served unmetered.
hosted_admission_unavailableThe capacity admission check could not complete, for example during a rate-limit store outage.
hosted_evidence_unavailableThe usage record that must exist before serving could not be written. No charge is incurred.
hosted_inference_unavailableThe model could not be served on this route. Retry shortly; contact support if it persists.
datastore_unavailableThe record the request depends on could not be read or written. Congestion alone is not this error and answers 429 hosted_admission_congested instead.
idempotency_unavailableYour Idempotency-Key could not be checked, so the request was refused rather than risk running twice. Retry after Retry-After with the same key.
billing_settlement_errorUsage settlement did not complete.
pricing_unavailablePricing for the target could not be resolved.
upstream_http_errorThe model answered the request with an HTTP failure. When the model's side supplied a Retry-After, it is forwarded unchanged; if the header is absent, back off briefly before retrying.
upstream_errorThe open-models service could not reach the model for this request and did not complete it.

Retired plan limit recovery

Coding plans are retired for new customers. For existing holders of the open-models service, a serving coding plan returns 402 plan_limit_reached when a plan window is at its limit and neither credits nor Standby can serve the request. The response carries x-should-retry: false and no Retry-After. It is a billing refusal; temporary Standby capacity refusals use 429 with retry timing.

The fields sit directly inside error, not under details. Read the blocking window, its exact counters, and the next step from your response.

Field inside errorMeaning
limitfive_hour or week. If both block, this identifies the blocking window that ends later, when both can admit again.
resets_atISO 8601 reset time for that window.
tierstarter, pro, or team.
used_microcents, limit_microcents, pending_microcentsThe blocking window's settled usage, limit, and in-flight commitments.
standby_resets_atISO 8601 daily refill time. A refill does not remove a payment or coverage restriction.
standby_blockerWhy Standby cannot serve: see below.
creditsCredits-after-limits choice, cap in cents, balance in cents, spending and pending maximum holds in microcents, and blocker.
fixesOne next step with a machine-readable code, display label, and url, chosen for the blocker and caller's permission.
standby_blockerMeaning
not_coveredStandby covers chat requests only.
payment_neededStandby is off until the plan payment goes through.
credits_owedStandby is off while the credit balance is negative.
closedStandby is unavailable.
exhaustedThe daily amount, including in-flight commitments, has no room.

credits.blocker is disabled, balance_negative, key_limit, empty, cap, or period_unavailable. An owner can receive Keep full speed on credits, Add funds, Raise the key limit, Raise the cap, or Contact support as the next step. A member receives Ask an owner.

The funding headers report x-runinfra-funding: refused. /v1/messages rewrites the body to error.type: "billing_error" and the message text, with request_id; the other plan fields are absent. In Messages clients such as Claude Code, read the message: it carries the limit, reset, Standby condition, and next step without an error.code. See Messages.

Envelopes that carry more than the table

Credit fields are in cents. Read current_balance_cents, required_cents and topup_url from the response.

Add at least required_cents - current_balance_cents, then retry. topup_url is absolute.

When the workspace has a coding plan that is not paying for requests (a payment is overdue, or a payment dispute paused it), message ends with the plan's state and its next step, such as paying the overdue amount, or contacting support.

A free_window_ended_at field appears only when the model you called was on a promotional free window that closed within the last seven days, as a UTC RFC 3339 instant describing the same close the message states in words. When there is no recently closed window the field is absent rather than null, which is the usual case. The same field accompanies a 402 account_frozen under the same rule. A model's price, and whether it is inside a free window, live on that model's page, never here.

402 spend_limit_reached, with the limit, the spend, and the reset instant

A per-key monthly spending limit is optional and set by the key's owner under Settings, API keys. It is enforced on the key's settled spend in the current calendar month (UTC), so a request already in flight when the limit is reached may still complete. Amounts are in cents. These values are an example.

JSON
JSON
{
  "error": {
    "limit_cents": 5000,
    "spent_cents": 5000,
    "resets_at": "2026-10-01T00:00:00.000Z",
    "message": "This API key has reached its monthly spending limit of $50.00 ($50.00 settled this month). Raise or remove the limit under Settings, API keys, or wait for the month to reset at 2026-10-01T00:00:00.000Z.",
    "type": "permission_error",
    "param": null,
    "code": "spend_limit_reached"
  },
  "request_id": "req_example_0011"
}

This describes the pay-as-you-go key limit. On a serving coding plan, the key limit blocks credits after plan limits; eligible plan or Standby usage can still run. See key payment settings. Other keys in the workspace are unaffected. Raise or remove the limit on the key, use another key, or retry after resets_at.

503 hosted_model_paused, with the next availability check

Retry-After is in seconds: the time until the next availability check, capped at one hour. Once that check time has passed, it is 60 seconds on every endpoint, so a client polls about once a minute instead of every second. The status and code stay the same.

A paused model is not a missing model. It still appears in GET /v1/models with availability: "paused", so treat this as retry and poll, never as a reason to drop the model id from your configuration.

422 idempotency_replay_unavailable, and why not to change the key

JSON
JSON
{
  "error": {
    "original_status": 200,
    "original_response_bytes": 25000000,
    "message": "The original response for this Idempotency-Key was too large to replay safely. Do not retry with a new key because that can start new paid work. Contact support with the request ID.",
    "type": "invalid_request_error",
    "param": "Idempotency-Key",
    "code": "idempotency_replay_unavailable"
  },
  "request_id": "req_example_0012"
}
Text
X-RunInfra-Idempotent-Replay: unavailable

A new key here would start new inference work and a second charge. Contact support with request_id instead.

400 hosted_parameter_not_supported on response_format

JSON
JSON
{
  "error": {
    "message": "This model cannot enforce response_format while it is reasoning, so the reply would not match the format you asked for and the request would be billed anyway. Send \"reasoning_effort\": \"none\" together with response_format, or remove response_format. On /v1/responses the same remedy is a top-level \"reasoning_effort\": \"none\" beside \"text\": {\"format\": ...}.",
    "type": "invalid_request_error",
    "param": "response_format",
    "code": "hosted_parameter_not_supported"
  },
  "request_id": "req_example_0020"
}

Send the request again with the effort the message names beside response_format, or drop the format. Check the selected model's current JSON requirements in A JSON format the model cannot hold while reasoning. Nothing is charged for the refusal, which is the point: the alternative is a 200 carrying a reply your parser rejects, billed in full.

429 hosted_admission_congested, a capacity shed

Under a momentary burst the gateway waits only briefly for capacity and then sheds the request rather than let it wait longer, so it never completes. That is a temporary capacity condition, not an outage and not a quota, so it answers 429.

JSON
JSON
{
  "error": {
    "message": "The gateway is at capacity and shed this request before completing it. This is a temporary condition on our side, not a problem with your request. Retry after the interval in the Retry-After header.",
    "type": "rate_limit_error",
    "param": null,
    "code": "hosted_admission_congested"
  },
  "request_id": "req_example_0018"
}

This answer applies on every /v1 route, so the same condition never surfaces as a different status elsewhere. The message varies with where the shed happened; the status, type and code do not. Unlike a hosted admission limit, a shed carries no limit field and no X-Hosted-Limit-Scope header, because there is no quota to size against.

401 or 403 on a key that looks correct

Browser or device sign-in with runinfra login creates a terminal key. It has the same rp_ prefix and 40 character body as a workspace API key and it cannot call the inference API, so it answers authentication_error with the message "This API key is internal and cannot be used for customer inference." Create a workspace API key in Settings, API keys.

HTML 403 security checkpoint

An HTML 403 security checkpoint instead of a JSON error means automatic traffic protection flagged your network. The response carries x-vercel-mitigated: challenge. Wait a few minutes before retrying, lower the request burst, and contact support if it persists.

Payload too large

The 32MB ceiling is enforced on the declared Content-Length and again while the body streams, so an understated Content-Length does not bypass it. It is a limit on the encoded request and is separate from the model context window: split the prompt across requests or send less context.

A body above 32MB gets the same JSON 413 payload_too_large, with a request id, after the upload finishes. The one exception is a request above about 4MB that has no Content-Length header: the platform edge rejects it before the gateway sees it, with a 413 that carries no JSON envelope and no request id. Treat both as the same instruction: shrink the body, and send a Content-Length header (every SDK does).

Retry rules

  • Keep the same Idempotency-Key when you retry, streaming or not.
  • Respect Retry-After, or Retry-After-Ms if your client reads it, on every response that carries them.
  • On the hosted admission 429 codes the value is an estimate, capped at 8 seconds, and it changes between refusals. Add jitter if many workers share one key.
  • Do not replace the key after 422 idempotency_replay_unavailable.
  • A streaming retry never replays the delivered tokens. The same key returns 409 while the original is open, then the terminal usage and cost once it settles. See Idempotent retries.

Source reference