Errors and retries
Every error has an HTTP status, a stable code, and a message. Send the x-request-id header from the response when you contact support.


Error format
Errors use the OpenAI shape, so SDKs raise them with the message. Branch on code; the message may change.
{
"error": {
"message": "Model \"gpt-4o\" is not available. See GET /v1/models.",
"type": "model_not_found",
"code": "model_not_found"
}
}Codes
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request | The body is not valid JSON, misses model or messages, has an unknown role or reasoning_effort, has more than 8 images or an image URL that is not a public http(s) host or a data:image/ URL, or the model rejected a parameter (then the status can be another 4xx). | Fix the request. The message names the problem. |
| 401 | invalid_api_key | The key is wrong or missing. | Check the key and the Authorization header. |
| 402 | insufficient_balance | The balance cannot cover this request. | Top up, or set a lower max_tokens. |
| 402 | key_budget_exceeded | This key reached its monthly budget. | An admin raises the key budget, or use another key. A top-up does not help. |
| 402 | workspace_budget_exceeded | The key's workspace reached its monthly budget. | An admin raises the workspace budget. |
| 402 | org_budget_exceeded | The organization reached its monthly budget. | An owner raises the organization budget. |
| 402 | credit_limit_reached | A contract organization reached its credit limit. | Settle the open statement, or ask Worg to raise the limit. |
| 402 | playground_budget_exceeded | A console Playground key used its daily US$1. | Use an API key, or wait for the next day (WIB). |
| 403 | key_disabled | The key was revoked. | Create a new key. |
| 403 | key_expired | The key passed its expiry date. | Create a new key. |
| 403 | key_suspended | Suspended after unusual spend in the last hour. | An admin reviews it in API keys, then rotates or resumes it. |
| 403 | org_suspended | The organization is suspended. | Contact support. |
| 403 | org_not_approved | The account is waiting for review. | Wait for the approval email, or contact support. |
| 403 | model_not_allowed | This key may not use that model. | An admin changes the key's models, or use another key. |
| 404 | model_not_found | The model ID or combo is not available. | Use an ID from GET /v1/models. |
| 404 | not_found | The endpoint is not offered. | Use /v1/chat/completions or /v1/models. |
| 413 | body_too_large | The request body is over 16 MB. | Send a shorter request. |
| 413 | images_too_large | The lane refused the images in this request as too large. | Send smaller images (2,048 px on the longest side or less) or fewer of them. Through a combo, the next lane is tried first. |
| 429 | rpm_exceeded | Requests-per-minute limit of the key, its workspace or the organization reached. | Retry after the seconds in Retry-After. |
| 429 | tpm_exceeded | Tokens-per-minute limit of the key, its workspace or the organization reached. | Retry after 60 seconds (Retry-After). |
| 429 | concurrency_exceeded | Too many requests are running on this key or organization. | Retry when one finishes (Retry-After: 1). |
| 429 | capacity_busy | The lane is busy right now. | Retry after 5 seconds (Retry-After). Calling the model name alone or a combo lets Worg try another lane first. |
| 500 | internal | Something failed inside Worg. | Retry. If it repeats, send the x-request-id to support. |
| 502 | upstream_unavailable | Every lane Worg tried is temporarily unavailable. | Retry with backoff and check the status page. Calling the model name alone or a combo lets Worg try another lane first. |
In a stream that already started, a failure arrives as a chunk with an error object and code upstream_error. See Streaming.
Handling errors
Before an error reaches you, Worg has already done this:
- A server error or a dropped connection before the lane sends anything is tried once more on the same lane, after a short pause. Only the attempt that answers is billed. A lane that sends nothing within 60 seconds is not tried again.
- If the lane still fails, a model name alone moves to the other lane of the same model, and a combo moves to its next lane. A lane ID returns the error.
- Once the first chunk of a stream reaches you, nothing is retried or moved.
So 502 upstream_unavailable or 429 capacity_busy means every lane Worg tried has failed. Retry with backoff as below, and check status.getworg.com for an ongoing incident. If it continues, send the x-request-id of a failed response to support.
Retries
| Answer | Retry? |
|---|---|
| 429 | Yes, after the seconds in Retry-After. |
| 500, 502 | Yes, with exponential backoff: about 1, 2, 4 and 8 seconds, plus a random part. |
| 524 | The request ran over 100 seconds without sending anything. Retry with "stream": true. |
| Other 4xx | No. The same request fails the same way: fix it, top up, or change the key first. |
The official OpenAI SDKs already retry 408, 409, 429 and 5xx with backoff and wait for Retry-After. Raise their retry count and timeout, and branch on the error code for the rest:
import os
import openai
from openai import OpenAI
# The SDK retries 408, 409, 429 and 5xx with exponential backoff and honours Retry-After.
client = OpenAI(
base_url="https://api.getworg.com/v1",
api_key=os.environ["WORG_API_KEY"],
max_retries=4,
timeout=300,
)
try:
response = client.chat.completions.create(
model="deepseek-v4.1-flash:cached",
messages=[{"role": "user", "content": "Say hello in Indonesian."}],
max_tokens=512,
)
print(response.choices[0].message.content)
except openai.APIStatusError as e:
# Branch on the code, not the message. Keep x-request-id for support.
print(e.status_code, e.code, e.response.headers.get("x-request-id"))
if e.code in ("insufficient_balance", "key_budget_exceeded"):
raise SystemExit("Top up or raise the budget, then run again.")
raise- A retry is a new request with its own bill. A stream that was cut after it started is billed for what the model wrote before the retry.
- Speed limits, budgets and the cost hold: Rate limits.
Next: Rate limitsStreaming