# Errors and retries Source: https://docs.getworg.com/errors 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. 404 response: ```json { "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](https://docs.getworg.com/streaming#errors). ## 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](https://docs.getworg.com/models#model-without-a-lane) moves to the other lane of the same model, and a [combo](https://docs.getworg.com/combos) 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](https://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: Python: ``` 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](https://docs.getworg.com/rate-limits). Next: [Rate limits](https://docs.getworg.com/rate-limits) ยท [Streaming](https://docs.getworg.com/streaming)