> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnia-voice.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Error codes Omnia returns and how to handle them.

Omnia returns standard HTTP status codes with OpenAI-style error bodies, so most
existing OpenAI-compatible client libraries can parse them without changes. Every
error response has the same shape:

```json theme={null}
{
  "error": {
    "message": "Human-readable description of what went wrong.",
    "type": "invalid_request_error",
    "code": "model_not_found"
  }
}
```

<ResponseField name="error.message" type="string">
  A human-readable description of the problem. Safe to log and surface to
  developers, but do not parse it programmatically; parse `type` and `code`
  instead.
</ResponseField>

<ResponseField name="error.type" type="string">
  The high-level error category. One of `invalid_request_error`,
  `insufficient_quota`, or `upstream_error`.
</ResponseField>

<ResponseField name="error.code" type="string">
  The specific machine-readable error. One of `invalid_api_key`,
  `insufficient_balance`, `model_not_found`, `dedicated_endpoint_not_found`, or
  `unknown_provider`. Branch on this value in your error handling.
</ResponseField>

## Status codes

| Status | Meaning                                                                         | What to do                                                               |
| ------ | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `200`  | Success.                                                                        | —                                                                        |
| `400`  | Bad request: malformed body, unsupported parameter, or unknown provider prefix. | Check your request shape and provider prefix.                            |
| `401`  | Unauthorized: missing, malformed, or revoked API key.                           | Verify your key and `Authorization` header.                              |
| `402`  | Insufficient balance to cover the request's worst-case hold.                    | [Top up](/billing/wallet) or enable [auto-reload](/billing/auto-reload). |
| `404`  | Model or dedicated endpoint not found.                                          | The model isn't in the priced catalog, or the routing key is wrong.      |
| `408`  | Request timed out.                                                              | Retry with backoff; check for very large requests.                       |
| `429`  | Rate limited.                                                                   | Back off and retry; see [Rate limits](/reference/rate-limits).           |
| `502`  | Upstream error.                                                                 | Transient provider issue; retry with backoff.                            |

## Error codes

The `type` and `code` fields pinpoint the exact failure. Use the table to map a
`code` to its category, HTTP status, and remedy.

| `code`                         | `type`                  | Status | Meaning                                                              |
| ------------------------------ | ----------------------- | ------ | -------------------------------------------------------------------- |
| `invalid_api_key`              | `invalid_request_error` | `401`  | Key is missing, malformed, or revoked.                               |
| `insufficient_balance`         | `insufficient_quota`    | `402`  | Wallet can't cover the request's worst-case hold.                    |
| `model_not_found`              | `invalid_request_error` | `404`  | Model isn't in the priced catalog.                                   |
| `dedicated_endpoint_not_found` | `invalid_request_error` | `404`  | Dedicated routing key isn't owned by your workspace, or was deleted. |
| `unknown_provider`             | `invalid_request_error` | `400`  | Provider prefix has no configured key.                               |
| —                              | `upstream_error`        | `502`  | Transient error reaching the model provider.                         |

<AccordionGroup>
  <Accordion title="invalid_api_key (401)" icon="key">
    The key is missing, malformed, or revoked. Keys are sent as
    `Authorization: Bearer <key>`. Confirm the header is present and the key is
    active in your workspace. Rotating a key immediately invalidates the old
    one, so deployments still holding a stale key will see this error.
  </Accordion>

  <Accordion title="insufficient_balance (402)" icon="wallet">
    Before a request runs, Omnia places a hold on your wallet for the request's
    **worst-case** cost, enough to cover the maximum tokens it could produce. If
    the wallet can't cover that hold, the request is rejected with `402` before
    any provider is called. You're never charged for a request that returns
    `402`. Add funds or turn on [auto-reload](/billing/auto-reload) to avoid
    interruptions. Capping `max_tokens` also lowers the hold, since the
    worst case shrinks.
  </Accordion>

  <Accordion title="model_not_found (404)" icon="magnifying-glass">
    The model you requested isn't in the priced catalog: either the id is
    misspelled or the model isn't offered. This is a **deliberate** `404`: Omnia
    refuses to run a model it can't price so you're never billed for an unpriced
    model. Call [`/v1/models`](/concepts/models) to list valid ids.
  </Accordion>

  <Accordion title="dedicated_endpoint_not_found (404)" icon="server">
    You addressed a dedicated endpoint as `dedicated/<routing-key>`, but that
    routing key either isn't owned by your workspace or has been deleted. Check
    the routing key on the endpoint's page in the dashboard, and confirm the
    endpoint still exists. See [Dedicated endpoints](/dedicated/overview).
  </Accordion>

  <Accordion title="unknown_provider (400)" icon="triangle-exclamation">
    You used a provider prefix that has no configured key. Verify the provider
    prefix is spelled correctly and that a key for that provider is configured
    for your workspace.
  </Accordion>

  <Accordion title="upstream_error (502)" icon="cloud">
    A transient error reaching the model provider. Retry with exponential
    backoff. The message includes a request id reference; quote it if you
    contact support.
  </Accordion>
</AccordionGroup>

## Retrying safely

Retry `429`, `408`, and `502` responses with exponential backoff and jitter.

<Tip>
  Completions are **safe to retry**: you're only billed for tokens actually
  produced. A retried request that never returned tokens costs nothing.
</Tip>

For a `502`, the `message` includes a request id reference. Quote that reference
if you contact support so the request can be traced.

<Warning>
  Don't blindly retry `4xx` errors other than `408` and `429`. A `400`, `401`,
  `402`, or `404` means the request itself needs to change; retrying it
  unchanged will fail the same way every time.
</Warning>

### Python

This helper retries only the transient statuses and backs off exponentially with
jitter:

```python theme={null}
import time
import random
import httpx

RETRYABLE = {408, 429, 502}

def call_with_retry(client, payload, retries=5):
    for attempt in range(retries):
        resp = client.post("/v1/chat/completions", json=payload)
        if resp.status_code == 200:
            return resp.json()

        if resp.status_code not in RETRYABLE or attempt == retries - 1:
            # Non-retryable, or out of attempts: raise with the parsed error.
            err = resp.json().get("error", {})
            raise RuntimeError(
                f"{resp.status_code} {err.get('code')}: {err.get('message')}"
            )

        # Exponential backoff capped at 30s, plus jitter to avoid stampedes.
        sleep = min(30, 2 ** attempt) + random.random()
        time.sleep(sleep)
```

### curl

`curl --retry` with backoff covers the transient cases for simple scripts:

```bash theme={null}
curl https://gateway.omnia-voice.com/v1/chat/completions \
  -H "Authorization: Bearer $OMNIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "Qwen/Qwen3-32B", "messages": [{"role": "user", "content": "Hi"}]}' \
  --retry 5 \
  --retry-delay 1 \
  --retry-all-errors
```

## Inspecting errors after the fact

Every failed request appears in the dashboard's request log, and the
**Errors by cause** breakdown groups failures by category (rate limits,
timeouts, upstream errors). See [Observability](/reference/observability) to
diagnose patterns across many requests rather than one at a time.
