# Errors

When an Inovacc API refuses or cannot complete a call, it answers with an HTTP status and a JSON error envelope. This guide describes the envelope, the error types, the codes that every API shares, and what to do for each status: fix the request, wait, or retry.

## The envelope

```json
{ "error": { "message": "Human-readable explanation", "type": "validation_error", "code": "invalid_body" } }
```

- **`code`** is what your program should branch on. Codes are part of each API's contract: within a version path such as `/v1`, new codes may be added, and an existing code keeps its meaning.
- **`type`** groups codes into families, useful for logging and broad handling.
- **`message`** is a fixed English sentence for people. It never repeats a value from your request (at most the name of a refused field) and never describes what failed inside Inovacc. Do not parse it.

Some answers add a field to the envelope: a refused file carries `reason` (for example `executable` or `password_protected`), and a schema conversion that does not fit carries `failing_documents`, a count. Ignore fields you do not know.

Two answers do not use the envelope. On the AI API, a path that does not exist answers `404 {"error":"not_found"}`. A WebSocket (an Events stream or a Data listener) refused before the upgrade answers an ordinary HTTP error; once open, it ends with a close code.

## Types

| `type` | Means | Typical status |
|---|---|---|
| `validation_error` | The request is malformed: a header, a field or a value breaks the rules. | 400 |
| `invalid_request_error` | The request is well formed but cannot be served as sent: too large, an unsupported file type, a URL that may not be fetched. | 400, 413, 415, 422 |
| `authentication_error` | No credential, or one that is not valid. | 401 |
| `authorization_error`, `permission_error`, `forbidden` | The credential is valid but may not do this. | 403 |
| `not_found_error`, `not_found` | The thing does not exist, or you may not know it exists. | 404, 410 |
| `conflict_error`, `conflict` | The request conflicts with the current state: a version, a mode, a limit on a collection. | 409 |
| `idempotency_error` | An operation id is in use or was used for something else. | 409 |
| `rate_limit_error`, `rate_limited` | Too many calls, or an allowance or budget is spent. | 429 |
| `api_error`, `service_error`, `service_unavailable`, `internal_error` | Something on Inovacc's side, or a source it called for you, failed. | 500, 502, 503, 504 |

The Data, AI and Events APIs use the families above; the exact `type` string can differ between APIs for the same family, so handle the `code`, and fall back on the HTTP status.

## Codes every API shares

| Status | Code | Meaning | What to do |
|---|---|---|---|
| 401 | `missing_credentials`, `invalid_credentials` | No key, or a key that is not valid, expired or revoked. | Fix the credential; do not retry unchanged. |
| 403 | `forbidden`, `route_forbidden`, `key_disabled`, `capability_not_enabled` | The credential may not do this. | Ask for the permission, route or capability. |
| 403 | `origin_not_allowed`, `secret_key_in_browser` | A browser call from an origin not listed, or a secret key in a browser. | List the origin; use a publishable key. |
| 400 | `missing_operation_id`, `invalid_operation_id` | AI: a `POST`, `PUT` or `DELETE` without a valid `X-Operation-Id`. | Send 8 to 128 letters, digits, `_` or `-`. |
| 400 | `invalid_body`, `unsupported_field`, `invalid_field` | The body or a parameter is not valid for this endpoint. | Fix the request. |
| 404 | `*_not_found` | It does not exist, or it is not yours. | Check the id. |
| 409 | `operation_in_progress` | The same operation id is still running. | Wait, then retry with the same id. |
| 409 | `operation_id_reused` | AI: an operation id already used for a different file in a collection. | Use a new operation id for a new operation. |
| 409 | `version_conflict` | Data: the record changed since you read it. | Re-read, then retry. |
| 413 | `request_too_large`, `payload_too_large` | The body is over the size limit. | Make it smaller, or upload in parts. |
| 429 | `rate_limited` | Too many requests in the window. | Wait `Retry-After` seconds, when given. |
| 429 | `quota_exceeded`, `concurrency_limited` | AI: a token, cost or concurrency allowance is used up. | Slow down; raise the allowance with Inovacc. |
| 429 | `budget_exhausted` | AI: a daily budget is spent. | Wait until 00:00 UTC (`Retry-After`). |
| 502 | `upstream_error` | A source called for you failed. | Retry with backoff. |
| 503 | `service_unavailable` | A dependency could not be reached; nothing was done or guessed. | Retry with backoff. |
| 504 | `timeout_error` | AI: the model did not start answering in time. | Retry with backoff. |

Each product page lists every code it can return, with what to do.

## Retry policy

| Status | Retry? | How |
|---|---|---|
| 400, 401, 403, 404, 410, 413, 415, 422 | No | The same request will fail the same way. Fix it first. |
| 409 `operation_in_progress` | Yes | After a short wait, with the **same** operation id. |
| 409 `version_conflict` | Yes, after re-reading | Read the record, apply your change to the new version, send its `If-Match`. |
| 409, other codes | No | The state must change first (create the database, wait for items, empty the folder). |
| 429 with `Retry-After` | Yes | Not before the number of seconds it gives. |
| 429 without `Retry-After` | Later | An allowance is used up: back off for minutes, not seconds, or raise it. |
| 500, 502, 503, 504 | Yes | With exponential backoff and jitter (for example 1, 2, 4, 8 seconds), a few times at most. |
| Network error, no answer | Yes | As for 503. |

**Retry safely.** On the AI API, retry a mutating call with the **same** `X-Operation-Id`: if the first attempt did succeed, you receive its stored answer instead of a second run. On Data, retry a create with your own record id or `If-None-Match: *`, and an update with the same `If-Match`. On Events, retry a publish with the same `idempotency_key`: the original `event_id` comes back with `duplicate: true`.

## See also

- [Authentication](/en/guides/authentication/): credentials and idempotency.
- [Limits](/en/guides/limits/): the sizes and rates behind `413` and `429`.
- [Webhooks](/en/guides/webhooks/): how failed deliveries are retried.
