> ## 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 an `error` message and a machine-readable
`error_code`:

```json theme={null}
{ "error": "request must be multipart/form-data with a `config` part followed by an `audio` part", "error_code": "bad_request" }
```

Errors relayed from the transcription service use a different shape, with
`status`, `title`, and `detail` fields. Read both when surfacing an error:

```json theme={null}
{ "status": 404, "title": "Not Found", "detail": "Invalid API key" }
```

## Status codes

| HTTP | Body shape                    | Cause                                                                                                                                                |
| ---- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400  | `error` / `error_code`        | Missing or empty `audio` part, a missing `config` part or one sent after `audio`, malformed `config` JSON, or a `config` field that fails validation |
| 401  | `error` / `error_code`        | No credential supplied                                                                                                                               |
| 404  | `status` / `title` / `detail` | Invalid API key                                                                                                                                      |
| 413  | `error` / `error_code`        | Audio exceeded the size cap (`audio_too_large`)                                                                                                      |
| 415  | `status` / `title` / `detail` | The `audio` part is not `audio/wav` or `audio/pcm`                                                                                                   |
| 429  | `error` / `error_code`        | Rate limit exceeded                                                                                                                                  |
| 502  | `error` / `error_code`        | Transcription upstream unavailable                                                                                                                   |
| 503  | `error` / `error_code`        | Server at capacity (`capacity_exceeded`)                                                                                                             |
| 504  | `error` / `error_code`        | Transcription upstream timed out                                                                                                                     |

<Note>
  An invalid API key returns `404`, not `401`. Treat any `404` from this
  endpoint as an auth failure rather than a missing route.
</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 and 404** are credential problems. 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.
