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

# Errors

> Error response shape, codes, and how to handle failures.

## Response envelope

Every response uses a consistent envelope. **Success:**

```json theme={null}
{ "success": true, "data": { /* ... */ } }
```

**Failure** — `success: false`, `data: null`, and an `error` object with a
machine-readable `code`:

```json theme={null}
{ "success": false, "data": null, "error": { "code": "UNAUTHORIZED" } }
```

Always branch on the HTTP status first, then read `error.code` for specifics.

## Common HTTP statuses

| Status | Meaning                 | What to do                                                                         |
| ------ | ----------------------- | ---------------------------------------------------------------------------------- |
| `400`  | Malformed request       | Fix the request body/parameters.                                                   |
| `401`  | Missing/invalid API key | Check the `X-API-Key` / `Authorization` header.                                    |
| `402`  | Out of credits          | You've used your cycle's credits — see [Rate limits & quota](/guides/rate-limits). |
| `413`  | Payload too large       | Shorten `text`, or reduce the ASR audio file.                                      |
| `415`  | Unsupported media       | Use a supported audio format (see [ASR](/models/asr)).                             |
| `422`  | Validation error        | A field failed validation (e.g. `text` length).                                    |
| `429`  | Too many requests       | Back off and retry — see [Rate limits](/guides/rate-limits).                       |
| `5xx`  | Server error            | Transient; retry with backoff.                                                     |

## Handling errors

```python Python theme={null}
resp = requests.post(url, headers=headers, json=payload)

if resp.status_code == 429:
    # rate limited — wait and retry
    ...
elif not resp.ok:
    body = resp.json()
    code = (body.get("error") or {}).get("code")
    raise RuntimeError(f"{resp.status_code} {code}")
```

<Note>
  Streaming endpoints (`/v1/speech/synthesize`) signal failures with a non-200
  status **before** the stream starts. Once a `200` NDJSON stream begins, check
  for an error record/early close if the connection drops mid-stream.
</Note>

## Retries

Retry `429` and `5xx` with **exponential backoff** (e.g. 1s, 2s, 4s) and a cap.
Do **not** retry `4xx` other than `429` — fix the request instead.
