# Errors

A name nobody serves, a capability nobody has and an upstream that broke are three different statuses, so you can tell them apart without parsing prose. Only one of them is worth retrying.

## Statuses

| Status | Cause | What to do |
|---|---|---|
| `401` | No authenticated caller. | Check the `Authorization` header. The `GET /models/...` catalogs need no token. |
| `404` | No configured model answers to that name, or none that does runs on a key you hold or one Momor resells. | Read the catalog. The name is wrong, that model is not configured here, it is a model of another type than the route serves, such as a decision model sent to `/models/chat`, or none of its rows says `resale: true` and you sent no key of your own for its providers. Under [zero data retention](/docs/gateway/bring-your-own-keys/#zero-data-retention), only saved keys marked `zdr` and Momor's keys its own agreements cover count. |
| `400` | Invalid JSON or a public-contract validation failure. | Fix the request. Numeric enums, stored handles and internal tool-routing kinds are rejected. A property Momor does not read is ignored, and a parameter value is never checked against a provider's range. Under zero data retention, `fileProcessing` other than `none` is refused. |
| `406` | `Accept` does not allow the response selected by `streaming`. | Allow `application/json` for unary calls or `text/event-stream` for streams. `Accept` never changes execution mode. |
| `413` | The request body or inline-file limits were exceeded. | Send large files by URL rather than inline bytes. Public file handles are rejected. |
| `415` | The request is not `application/json`. | Set `Content-Type: application/json`. |
| `422` | Models matched, and every one refused this request. | A capability you asked for is not offered — tools, a schema, streaming or a file type. Retrying will not help. |
| `429` | The caller exceeded the gateway's request-rate limit. | Read `Retry-After` and `X-RateLimit-Reset` before retrying. |
| `503` | The candidate ladder was exhausted by provider/transport failures. | Retry after a delay or broaden the selector. |
| `504` | The provider did not answer within the call's network timeout, or within the gateway's own limit. | Retry, or broaden the selector to a faster model. A `networkTimeout` you set only ever shortens the wait. |
| The provider's own | Every candidate was tried and failed upstream. | The status and message are the provider's, passed through. Treat it as you would treat that provider directly. |
| `502` | A stream opened and produced nothing, or ended without a terminal event. | Safe to retry. Arrives as an error frame inside the stream, not as an HTTP status. |
| `502` | A provider refused the key you sent or saved for it. | Check the key with the provider. The message names the provider. |

## Error bodies

Unary failures are RFC 7807 problem documents. Streamed failures are frames on the stream, because the HTTP status
was already sent when the stream opened.

```http
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
{
  "status": 404,
  "detail": "No configured model answers to claud-sonnet-5."
}
```

```http
event: error
data: {"success":false,"code":502,"message":"Stream ended without a terminal event."}
```

## The messages you will see

| `detail` | Meaning |
|---|---|
| `No configured model answers to <name>.` | Nothing in the catalog matches the name, tier and provider you asked for, in the system the route names. A model not yet classified is never served, and a tier, `auto` or `*` also leaves out deprecated models and those released on or before the cut-off. |
| `No configured model answering to <name> runs on a key the caller or Momor holds.` | `404`. Models matched, and none of them runs on your own key or on a key Momor resells. Send your key for one of its providers in [`keys`](/docs/gateway/bring-your-own-keys/#send-a-key-with-a-call), or choose a model whose catalog row says `resale: true`. Under [zero data retention](/docs/gateway/bring-your-own-keys/#zero-data-retention), that is a saved key marked `zdr` or a Momor key its own agreements cover; a key sent with the call is not used. |
| `No configured model supports this request.` | Models matched the selector, but none could carry every capability the request requires. Read the catalog to compare tools, structured output, streaming and content types. |
| `<model> requires MaxTokens.` | The Anthropic API requires an output ceiling. Set `parameters.maxTokens`. |
| `<model> requires max_tokens.` | The same ceiling on a [Chat Completions](/docs/gateway/reference/chat-completions/) call. Set `max_tokens` or `max_completion_tokens`. |
| `<model> has no block for <type> content here.` · `<model> has no part for <type> content.` | Anthropic or Gemini has no way to carry that part of a Chat Completions call. The call moved on to the next candidate; this is the answer only where no candidate could carry it. |
| `prioritization names <provider>, which this deployment does not serve.` | Read the catalog's `provider` values. A region is named `name@region`, such as `azure@eu`, and must be one the deployment serves. |
| `prioritization both orders and ignores <provider>.` | Name a provider in `order` or `ignore`, not both. |
| `'provider.zdr' must be a boolean.` | `400`. On [Chat Completions](/docs/gateway/reference/chat-completions/), `provider.zdr` is `true` or `false`. |
| `keys names <provider>, which this deployment does not serve.` | Send keys only for providers the catalog lists. |
| `<provider>@<region> serves no model that runs on a caller's own key.` | `400`. A key cannot be saved for that region alone. Save it for the root, which runs the root and all its regions. |
| `<provider> has no model a key for it is tried against.` | That provider's key cannot be saved or tested. It still works per call, sent in `keys`. |
| `<provider> refused the caller's own key for it: …` | `502`. The provider turned your key away; check it with the provider. |
| `<provider> is rate-limiting the caller's own key: …` | `429`. The limit is your key's own; wait it out or send no key. |
| `A decision carries its questions as systemPrompt, an array of at least one question.` | `POST /models/decision` takes `systemPrompt` as an array of questions, and at least one. |
| `A decision takes no stream, tools or responseSchema.` | Leave `streaming`, `tools` and `responseSchema` out of a decision. |
| `Every question needs a name of its own.` | Give each question a `name`, and no two the same. |
| `Question <name> needs instructions.` | Say what the question asks in `instructions`. |
| `Question <name>'s criteria do not fit a <type>: …` | A `boolean` explains `true` and `false`, a `choice` explains at least two values, and a `score` lists two to ten levels, lowest first. |
| `<model> decides on text alone, not <type>.` | The provider's `400`, ending `by address` where the file came as a URL. That decision model reads a text or JSON file as it is, and any other file only as the text it was parsed to. |
| `<model> decides on text and inline images alone, not <type>.` | The provider's `400`, ending `by address` where the file came as a URL. Send an image, text or JSON file inline, or have any other file parsed to text. |
| `<model> decides on user messages alone.` | The provider's `400`. A decision reads the user's messages only; leave the model's turns and tool results out. |
| `A transcription carries one recording, an audio file attached to a user message.` | `POST /models/transcribe` and `POST /v1/audio/transcriptions` take exactly one `audio/*` file. |
| `A transcription takes no stream, tools or responseSchema.` | Leave `streaming`, `tools` and `responseSchema` out of a transcription. |
| `<model> transcribes a recording sent with the call, not one by address.` | The recording came as a URL. Send it inline, or as a file Momor holds. |
| `'response_format' is json or text.` | `POST /v1/audio/transcriptions` answers `json` or `text`. |
| `<model> takes at most <count> options a question.` · `<model> takes at most <count> choices a question.` | The provider's `400`. That decision model takes no more options in one question: 24 on Tev1, 255 choices on Jev. |
| `<model> answered <question> with '<letter>', which is not one of its option letters.` | `502`. The model answered outside the options it was given; safe to retry. |

Capability refusals remain internal. Several candidates can refuse for different reasons, so the aggregate does not
select one candidate's explanation and present it as the answer for the whole ladder.

`status` is the machine-readable contract. `detail` is present on router-originated failures; framework rejections
such as an unsupported content type can instead carry a `title`. Problem `type` and tracing headers are not yet a
stable Gateway contract.

## Upstream failures

A provider's own status and message reach you unchanged, so you get its rate-limit, overload and content-policy
signals rather than a translation of them. Handle them as you would handle that provider directly.

> **Known rough edge**
> For OpenAI-compatible providers whose error body is not OpenAI's error object, the message is the client library's
> rendering of the failure rather than the provider's bare text, so it can read like `Service request failed.`
> followed by the status. The status is correct; the prose is noisier than it should be.

## What is worth retrying

| Outcome | Retry? |
|---|---|
| `400` · `401` · `404` · `406` · `413` · `415` · `422` | No. The request is wrong, or the deployment cannot serve it. |
| `502` | Yes, unless a provider refused your own key. |
| `503` | Yes, after a delay. |
| `504` | Yes, or with a wider selection. |
| Provider `429` / `5xx` | Only after a delay, or with a wider selection. |

Before returning any upstream failure, Momor has already stepped through every other model that could have served
the request. You are not being asked to do the failover — you are being told it was exhausted.
