---
title: "Handle errors and retries"
description: "Handle stable API error codes and avoid creating duplicate alignment jobs."
generated: true
---

# Handle errors and retries

```json
{ "error": { "code": "api_rate_limited", "problem": "...", "reason": "...", "fix": "..." } }
```

## Choose what to retry

Every error has the same shape, and `code` is stable, so branch on it:

| Status | Codes you will see | What to do |
| --- | --- | --- |
| `400` | `bad_request` | Fix the request; `fix` says how. Do not retry it as it is. |
| `401` | `api_unauthorized` | Check the key your server sends. A rolled key past its grace period says when it expired; use the key that replaced it. |
| `403` | `api_suspended` | Requests are paused on the account; contact Fellowverse to restore it. |
| `404` | `api_upload_missing`, `api_job_missing`, `api_file_expired` | The id is wrong, belongs to another account, or its files have been removed. |
| `429` | `api_rate_limited`, `api_test_quota` | Wait and retry. For `api_test_quota`, `fix` says when the day's allowance resets. |
| `5xx` | `internal`, `api_stt_off` | Retry after a short wait, doubling it each time. Typed search keeps working while voice search is unavailable. |

A failed alignment job carries its code in `error`: `api_audio_unreadable` for a file that cannot be read, `api_audio_too_long` for a recording over the length an alignment takes, `api_text_mismatch` when the audio does not read the text, and `api_passage_unknown` for a recording sent without text that is not a Bible reading. These fail at once; send a different file or text rather than the same job again.

`problem`, `reason` and `fix` are written to be read, so you can log them as they are or show `problem` and `fix` to your own team. Searches are safe to retry. Before retrying `POST /v1/alignments` after a timeout, check whether the first request made a job, so the same recording is not aligned twice.
