> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.narilabs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.narilabs.com/_mcp/server.

# Errors and troubleshooting

## Error response

Failed HTTP requests return a non-2xx status with a JSON error:

```json
{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "The speech request is invalid",
    "requestId": "019c2e72-149f-733a-9579-67df595ba0f0"
  }
}
```

| Field       | Use                                                                              |
| ----------- | -------------------------------------------------------------------------------- |
| `code`      | An `UPPER_SNAKE_CASE` identifier for handling the error in your application.     |
| `message`   | Read the explanation; do not match its wording in code.                          |
| `requestId` | Identify the request in logs or when contacting support. Matches `x-request-id`. |

## HTTP errors

These errors apply to HTTP requests and failed WebSocket handshakes.

| Status | Code                                                                                                                                                                                         | What to do                                                                         |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| 400    | `INVALID_REQUEST`                                                                                                                                                                            | Correct the fields described in `message`.                                         |
| 401    | `INVALID_API_KEY`                                                                                                                                                                            | Check your [API key and Authorization header](/authentication).                    |
| 402    | `INSUFFICIENT_CREDITS`                                                                                                                                                                       | Add credits or use a Free model.                                                   |
| 403    | `PARTNER_ACCESS_REQUIRED`                                                                                                                                                                    | Request Partner access or use a Free model.                                        |
| 404    | `MODEL_NOT_FOUND`                                                                                                                                                                            | Use a supported [model ID](/models-and-pricing).                                   |
| 413    | `REQUEST_TOO_LARGE`                                                                                                                                                                          | Reduce the complete JSON body to at most 65,536 bytes.                             |
| 429    | `CONCURRENCY_LIMIT_EXCEEDED`                                                                                                                                                                 | Wait for an in-flight request to finish before retrying.                           |
| 429    | `FREE_DAILY_LIMIT_EXCEEDED`                                                                                                                                                                  | Wait until 00:00 UTC, or use a Partner model if you have early access and credits. |
| 429    | `UPSTREAM_RATE_LIMITED`                                                                                                                                                                      | Retry with backoff.                                                                |
| 500    | `INTERNAL_ERROR`                                                                                                                                                                             | Retry with backoff; contact support with the request ID if it persists.            |
| 503    | `SERVICE_UNAVAILABLE`, `AUTH_BACKEND_UNAVAILABLE`, `RATE_LIMIT_UNAVAILABLE`, `REQUEST_GATE_UNAVAILABLE`, `UPSTREAM_UNAVAILABLE`, `SERVER_NOT_READY`, `SERVER_AT_CAPACITY`, `SERVER_DRAINING` | Retry with backoff.                                                                |

For transient failures, increase the delay between retries and add a small random delay to avoid simultaneous retries. Set a maximum retry count. See [Free tier and rate limits](/rate-limits) for allowance and concurrency policies.

#### Inspect a cURL error

If the [TTS quickstart](/quickstart) request fails, rerun it without `--fail` and `--output speech.wav` to display the JSON error in your terminal.

## WebSocket failures

After a successful handshake, STT reports errors as an `error` event before closing the connection:

```json
{
  "type": "error",
  "event_id": "event_123",
  "error": {
    "code": "EXPECTED_SESSION_CONFIGURE",
    "message": "the first client event must be session.configure",
    "requestId": "019c2e72-149f-733a-9579-67df595ba0f0"
  }
}
```

Use `error.code` to identify the cause. `error.requestId` matches the handshake's `x-request-id`.

| Code                                                                                          | What to do before reconnecting                                                                                                                                 |
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EXPECTED_SESSION_CONFIGURE`                                                                  | Send `session.configure` as the first client event.                                                                                                            |
| `SESSION_SETUP_TIMEOUT`                                                                       | Prepare to send the configuration within 10 seconds of connecting.                                                                                             |
| `SESSION_CONFIGURATION_LOCKED`                                                                | Open a new connection to use different settings.                                                                                                               |
| `UNSUPPORTED_LANGUAGE`                                                                        | Choose a supported language from the [session reference](/api-reference/speech-to-text/realtime/realtime-transcription), or omit it for automatic recognition. |
| `INVALID_AUDIO`, `EMPTY_AUDIO`                                                                | Send nonempty base64 audio containing a whole number of PCM16 samples.                                                                                         |
| `AUDIO_CHUNK_TOO_LARGE`, `JSON_TOO_LARGE`                                                     | Split audio into smaller append events. See [audio input limits](/transcribe-audio#send-audio).                                                                |
| `INVALID_FRAME`, `INVALID_JSON`, `INVALID_EVENT`                                              | Send a JSON object in a text frame.                                                                                                                            |
| `INVALID_REQUEST`                                                                             | Include `session.model` and correct the fields described in `message`. Unknown session fields are rejected.                                                    |
| `UNSUPPORTED_EVENT`                                                                           | Use a supported client event from the [API reference](/api-reference/speech-to-text/realtime/realtime-transcription).                                          |
| `UNSUPPORTED_TURN_DETECTION`, `INVALID_TURN_DETECTION`                                        | Use the supported [VAD settings](/transcripts-and-turn-detection#automatic-turn-detection).                                                                    |
| `MODEL_NOT_SERVED`                                                                            | Check the selected model; contact support if a supported model is rejected.                                                                                    |
| `SESSION_IDLE_TIMEOUT`                                                                        | Reconnect when ready to send audio. The idle limit is 60 seconds without nonempty audio; waiting for a final result is exempt.                                 |
| `VAD_OVERLOADED`, `VAD_UNAVAILABLE`, `VAD_RUNTIME_ERROR`, `SERVER_DRAINING`, `INTERNAL_ERROR` | Reconnect with backoff.                                                                                                                                        |

#### WebSocket close codes

Network failures may close the connection without an error event. In that case, inspect the close code.

| Code            | Meaning and action                                                                                |
| --------------- | ------------------------------------------------------------------------------------------------- |
| `1000`          | Normal closure.                                                                                   |
| `1006`          | Abnormal closure observed by the client; reconnect if needed. The server does not send this code. |
| `1008`          | Invalid input or a session timeout; inspect the error event before reconnecting.                  |
| `1009`          | Message too large; reduce chunk size.                                                             |
| `1011`          | Server failure; reconnect with backoff.                                                           |
| `1012` / `1013` | Restart or temporary unavailability; reconnect with backoff.                                      |

## Interrupted streams

**TTS:** Check the HTTP status before treating the body as audio. A failure after streaming starts can interrupt the audio without a JSON error. Treat a failed read as incomplete delivery. Retrying generates the full text again; there is no resume offset.

**STT:** Reconnect, authenticate, and send a new session configuration. Keep completed transcripts already received. If you retained the audio for unfinished utterances, you can resend it; it receives new IDs and is not automatically deduplicated. Only a received `transcript.completed` event confirms a final transcript.