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

# Error reference

> What the Rime API returns when a request fails, per transport, and what to capture when you need support.

How a failure looks depends on the host you call. The model hosts on `api.rime.ai` return a request ID that you can quote to support. The `users.rime.ai` endpoints return a plain-text message and no request ID.

## Errors from the model hosts

`coda.api.rime.ai` and `mist.api.rime.ai` return these errors:

| Status | Body | Cause | Fix |
| :- | :- | :- | :- |
| `400` | JSON: `{"error": {"kind": "invalid_input", "message": "...", "requestId": "..."}}` | A value in the body isn't valid, for example an unknown `lang` | Fix the value that `message` names |
| `400` | JSON, as in the row above | The model or the language does not accept a `customLexicon`, or the list is too long or has an entry that is not well-formed | Look up the `message` in [Fix a rejected request](https://docs.rime.ai/platform/phoneme-control#fix-a-rejected-request) |
| `400` | Plain text that starts with `Invalid JSON body` | The body isn't valid JSON, or a required field is missing | Fix the body |
| `400` | Plain text: `Missing Accept header and audioFormat not provided` | The request has no `Accept` header | Set `Accept` to one of the [audio formats](https://docs.rime.ai/api-reference/coda/http.md#audio-formats) |
| `401` | Empty, with a `WWW-Authenticate: Bearer` header | The `Authorization` header is missing, or Rime doesn't accept the key | Check the key on the [API Tokens page](https://app.rime.ai/tokens) |

Every successful response carries an `x-request-id` header, and every JSON error carries the same ID as `error.requestId`. Log it, and send it to support when you report a problem. The plain-text `400` and the `401` carry no request ID.

## How failures reach you, per transport

This section and the rest of the page cover the `users.rime.ai` endpoints. Most of their failures return the reason as a **plain-text body**: the status code carries the class of failure and the body carries the message. Two exceptions return JSON with an `error` field: an unhandled `500` from `POST /v1/rime-tts`, and `/phonemize` failures after authentication. Branch on the status code and `Content-Type`, not the body shape. These responses carry no request ID, so an accurate UTC timestamp is the most useful thing to capture when something fails. Record everything under [what to send to support](#what-to-send-to-support) at the moment it happens.

| Transport | Where it fails | What you observe |
| :- | :- | :- |
| HTTP `POST /v1/rime-tts` | Any | HTTP status, plain-text body with the message |
| WebSocket `/ws3` | At the upgrade | The upgrade fails with an HTTP status and plain-text body. No WebSocket is established. |
| WebSocket `/ws3` | After the socket is open | Close code `1011`, with the message in the close reason. Where an HTTP equivalent applies the reason usually begins with it, for example `400: text is too long` |
| WebSocket `/ws` (raw audio) | Any | The same as `/ws3`: an HTTP status at the upgrade, or close code `1011` with the message in the close reason. `/ws` never sends JSON `error` events. |

Log the complete close reason string, because it's the only place the message appears. The leading status is a diagnostic aid, not a stable format, so read it but don't branch on it.

Handle both failure paths: the same bad request can be rejected on the upgrade with an HTTP status, or accepted and then closed with `1011` once the socket is open.

## 400, the request was rejected

| Message | Cause | Fix |
| :- | :- | :- |
| `request body is required` | No body sent | Send a JSON body |
| `payload must be an object` | Body parsed but is not a JSON object | Send an object, not an array or scalar |
| `text is required` | `text` is absent, not a string, or only whitespace | Send `text` as a non-empty string |
| `text is too long` | `text` exceeded 1,000 characters | Split into multiple requests at sentence boundaries |
| `speaker is required` | `speaker` absent | Include `speaker`. There is no default voice |
| `lang must be a string` | `lang` is not a string | Send a string such as `eng` or `en` |
| `audioFormat must be a string` | `audioFormat` is not a string | Send a string. See [Streaming formats](https://docs.rime.ai/docs/streaming.md) |
| `Language <lang> is not supported for model <model>` | The language is not in the model's supported set | Use a supported language for that model. See the [language matrix](https://docs.rime.ai/docs/voices.md#languages) |

> [!WARNING]
>
> **Do not rely on this error to catch a bad pairing.** It is not returned for every model or transport, so an unsupported combination of `speaker`, `modelId`, and `lang` can be accepted and synthesized rather than rejected. Verify the combination against the [Coda](https://docs.rime.ai/docs/voices-coda.md) or [Mist v3](https://docs.rime.ai/docs/voices-mist-v3.md) catalog before you ship it, and treat a successful response as no evidence that the pairing was valid.

`/textnorm` reports text problems with its own messages: `text must be a string`, `text must not be empty`, and `text exceeds max length of 10000 characters`.

## 401, authentication failed

| Message | Cause |
| :- | :- |
| `missing headers` | No `Authorization` header sent |
| `empty apikey` | The header is present but the key is empty |
| `invalid api key` | The key is not recognized |
| `invalid subscription` | The key resolves to an account with neither a valid subscription nor a positive balance |

`invalid subscription` arrives as a 401 rather than a 402 or 403, so a billing problem can look like an authentication problem. If your key is correct and unchanged, check the account's subscription and balance before regenerating credentials. Create and manage keys on the [API Tokens page](https://app.rime.ai/tokens); see [Authentication](https://docs.rime.ai/docs/api-authentication.md).

## 403, authenticated but not allowed

`access forbidden` means the credential is valid but the account may not use this endpoint or resource. Retrying won't help. Contact [support@rime.ai](mailto:support@rime.ai) if you expect access.

## 406, the requested media type cannot be produced

`modelId "<model>" can only be returned as streamed audio; set Accept to one of: ...` means `Accept` named a concrete type the API cannot produce for that model. Coda and Mist v3 return audio only. Set `Accept` to one of the listed types. Retrying won't help. The model hosts on `api.rime.ai` don't return `406`: they stream WAV instead.

## 429, too many requests

`Currently at websocket limit` is returned at the WebSocket upgrade when the account already has as many WebSocket connections open as Rime allows. The limit is on connections open at the same time, not on how fast you open them. An HTTP request can also return `429` when a key sends requests faster than its rate limit. Rime doesn't publish a connection limit, so don't design to a specific number.

Treat a 429 as a signal to back off: stop opening new connections, retry the upgrade after a delay, and reuse existing connections rather than opening one per utterance. Limits apply to the account as a whole, so on a team account, connections opened by one member count against the others.

> [!NOTE]
>
> Synthesis concurrency is separate from this connection limit, and it depends on your plan. See [rime.ai/pricing](https://www.rime.ai/pricing), or for a concurrency commitment for capacity planning, contact [support@rime.ai](mailto:support@rime.ai) rather than inferring one from what you observe.

## 500 and 502, the request failed on Rime's side

| Status | Message | Meaning |
| :- | :- | :- |
| 500 | `internal error`, `Internal error`, `Database error` | An unhandled server-side failure |
| 502 | `text normalization engine error` | The [text normalization](https://docs.rime.ai/docs/text-normalization.md) endpoint could not reach its engine |

These are the only failures where a retry is reasonable on its own. Retry with backoff, and see [the retry guidance](#retrying-safely) below before retrying anything that may already have produced audio.

If 500s, 502s, or timeouts persist across retries, check the [Rime status page](https://www.rimestat.us) for an incident in progress before you change your integration.

## Retrying safely

Retry a 500 or 502. Do not retry a 400, 401, or 403: the request will fail identically and, for 401, repeated attempts with a bad credential are indistinguishable from an attack.

For a 429, back off and retry the connection rather than the synthesis.

> [!WARNING]
>
> **Retries are billed as new synthesis.** Rime bills by characters synthesized, and each request is billed independently. If a connection drops partway through a long utterance, resynthesizing the full text incurs its full character count again. For long utterances, synthesize in sentence-aligned chunks and resume from the last chunk you received, so a retry only re-sends what was lost.

## What to send to support

Include all of the following when you report a failure. Redact your API key.

* The request ID, from the `x-request-id` header or `error.requestId`, if the response has one
* The UTC timestamp of the failure, to the second. Without a request ID, this is how support locates the request
* The endpoint you called
* `modelId`, `speaker`, and `lang` exactly as sent
* The HTTP status and the full plain-text body, or the WebSocket close code and its complete reason string
* A minimal request that reproduces it, with the key removed
* Whether any audio had already arrived when the failure occurred

## Related

* [API authentication](https://docs.rime.ai/docs/api-authentication.md): creating keys and the header format, for diagnosing 401s.
* [Voices](https://docs.rime.ai/docs/voices.md): the catalog to verify a `speaker`, `modelId`, and `lang` combination against.
* [Streaming formats](https://docs.rime.ai/docs/streaming.md): valid `audioFormat` values and their tradeoffs.
* [WebSockets](https://docs.rime.ai/docs/websockets.md): which endpoint reports structured errors and which does not.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.