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

# Error handling

> Dictation API error responses, status codes, and retry guidance.

Most errors return a JSON body with `status`, `title`, and `detail` fields:

```json theme={null}
{ "status": 401, "title": "Unauthorized", "detail": "Invalid API key" }
```

A second shape, with an `error` message and a machine-readable `error_code`,
is used only for the errors Dictation raises while parsing the request itself,
before the config is validated:

```json theme={null}
{ "error": "`config` is not valid JSON: Expecting property name enclosed in double quotes", "error_code": "bad_request" }
```

Read both when surfacing an error. In practice, checking `detail` first and
falling back to `error` covers every case.

## Status codes

| HTTP | Body shape                    | Cause                                                                                                                                            |
| ---- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| 400  | `error` / `error_code`        | A malformed request body: a missing or empty `audio` part, a missing `config` part or one sent after `audio`, or `config` that is not valid JSON |
| 400  | `status` / `title` / `detail` | A well-formed `config` that fails validation: an unknown field, a value out of range, or a field over its length limit                           |
| 401  | `status` / `title` / `detail` | Missing `Authorization` header, or an invalid API key                                                                                            |
| 413  | `status` / `title` / `detail` | Audio exceeded the size cap                                                                                                                      |
| 415  | `status` / `title` / `detail` | The `audio` part is not `audio/wav` or `audio/pcm`                                                                                               |
| 429  | `status` / `title` / `detail` | Rate limit exceeded                                                                                                                              |
| 502  | `status` / `title` / `detail` | Transcription upstream unavailable                                                                                                               |
| 503  | `status` / `title` / `detail` | Server at capacity                                                                                                                               |
| 504  | `status` / `title` / `detail` | Transcription upstream timed out                                                                                                                 |

<Note>
  Both auth failures return `401`. A missing header gives `detail: "Missing
      Authorization header"`, and a bad key gives `detail: "Invalid API key"`.
</Note>

## A failed rewrite is not a failed request

The transcript rewrite is best-effort and is never allowed to fail the call. If
the rewrite fails, the response is still `200`, `text` still holds the verbatim
transcript, `llm_response` is `null`, and `llm_error` says what went wrong:

| `llm_error` | Meaning                                           |
| ----------- | ------------------------------------------------- |
| `timeout`   | The rewrite passed its 5-second internal deadline |
| `error`     | The rewrite failed for another reason             |

Fall back to `text` when `llm_response` is `null`. Never treat a non-`null`
`llm_error` as a failed request. In the Python SDK, `result.final_text` already
does this: it returns the rewrite when there is one and the transcript
otherwise.

## Errors in the Python SDK

A failed request raises `DictationError`, which carries the pieces you need to
decide what to do next:

| Attribute     | Meaning                                                            |
| ------------- | ------------------------------------------------------------------ |
| `status_code` | The HTTP status from the table above                               |
| `error_code`  | The machine-readable code, when the response carried one           |
| `retry_after` | Seconds to wait, from the `Retry-After` header on a `429` or `503` |

```python theme={null}
import time

import assemblyai as aai

aai.settings.api_key = "<YOUR_API_KEY>"

try:
    result = aai.DictationTranscriber().transcribe_live("clip.wav")
except aai.DictationError as error:
    if error.retry_after:
        time.sleep(error.retry_after)
    raise RuntimeError(
        f"Dictation failed ({error.status_code}/{error.error_code}): {error}"
    )
```

`retry_after` is `None` when the response carried no `Retry-After` header, so
fall back to your own backoff rather than assuming a value is present.

## Retry guidance

* **429, 502, 503, and 504** are transient. Back off and retry.
* **400, 413, and 415** mean the request itself is wrong. Fix the audio or the
  config before retrying. See [Audio requirements](/docs/dictation/audio-requirements)
  for the constraints.
* **401** is a credential problem. Retrying will not help.

A chunked upload cannot be replayed, so keep the audio in memory if you want to
retry a failed request. Set the HTTP client timeout to 90 seconds; typical short
clips respond in under a second.

## Need help?

If you get stuck, contact our support team at
[support@assemblyai.com](mailto:support@assemblyai.com) or create a
[support ticket](https://www.assemblyai.com/contact/support). Include the
`session_id` from the response, or the failing request's timestamp and endpoint
if no response was returned, to help us look up your request.
