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

# Errors

> The error format and every error code the Avina Data API returns.

Every failed request returns the same JSON shape and an HTTP status in the `4xx` or `5xx` range.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "error": {
    "code": "invalid_request",
    "message": "filters.all.0: unknown field 'company.size'",
    "request_id": "req_8f2a61c09d4e7b3a5f10c2d8",
    "details": [
      { "field": "filters.all.0", "message": "unknown field 'company.size'" }
    ]
  }
}
```

**error.code** `string` *required*

A stable, machine-readable code. Branch on this.

**error.message** `string` *required*

A human-readable explanation of the first problem. Wording can change; do not parse it.

**error.request\_id** `string` *required*

The request's identifier, also in the `X-Request-Id` response header. Include it when you contact support.

**error.details** `object[]`

Every problem found, when there is more to say than `message`. Each item has a `message` and usually a `field`: the body field or path at fault, such as `limit`, `filters.all.0` or `criteria.2`.

## Error codes

| HTTP | `code` | Meaning | Retry |
| - | - | - | - |
| `400` | `invalid_request` | The request is invalid: an unknown or malformed field, a bad filter, a bad cursor, or malformed JSON. `details` names each problem. | No. Fix the request. |
| `401` | `invalid_api_key` | The API key is missing, invalid or revoked. | No |
| `402` | `usage_limit_reached` | The workspace has no credits left. Nothing was started or charged. | After adding credits |
| `403` | `permission_denied` | The workspace is not allowed to do this. `details` gives a reason, such as `contact_search_disabled`. | No |
| `404` | `not_found` | No such object in this workspace. Also returned for an ID that belongs to another workspace. | No |
| `409` | `idempotency_key_reused` | The `Idempotency-Key` was used with a different request, or its first request is still running. | If still running, shortly |
| `413` | `invalid_request` | The request body is larger than 100 KB. | No |
| `415` | `invalid_request` | The request body is not JSON. Send `Content-Type: application/json`. | No |
| `429` | `rate_limited` | Too many requests. | After `Retry-After` seconds |
| `500` | `internal_error` | Something went wrong on our side. | Yes, with backoff |
| `502` | `internal_error` | A dependency failed, for example while interpreting a query. | Yes, with backoff |
| `503` | `internal_error` | The API key could not be verified right now. | Yes, with backoff |
| `503` | `workspace_not_ready` | The workspace is still being set up. | Yes, later |
| `504` | `timeout` | The request took too long. | Yes, with the same `Idempotency-Key` |

## Handling errors in code

Branch on the HTTP status for whether to retry, and on `code` for what to tell the user.

```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import requests

class AvinaError(Exception):
    def __init__(self, status: int, body: dict):
        error = body.get("error", {})
        self.status = status
        self.code = error.get("code")
        self.request_id = error.get("request_id")
        self.details = error.get("details", [])
        super().__init__(f"{status} {self.code}: {error.get('message')} ({self.request_id})")

    @property
    def retryable(self) -> bool:
        return self.status == 429 or self.status >= 500

def check(response: requests.Response) -> dict:
    if response.ok:
        return response.json() if response.content else {}
    try:
        body = response.json()
    except ValueError:  # a proxy can return a non-JSON body
        body = {}
    raise AvinaError(response.status_code, body)
```

```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
class AvinaError extends Error {
  constructor(status, body) {
    const error = body?.error ?? {};
    super(`${status} ${error.code}: ${error.message} (${error.request_id})`);
    this.status = status;
    this.code = error.code;
    this.requestId = error.request_id;
    this.details = error.details ?? [];
  }
  get retryable() {
    return this.status === 429 || this.status >= 500;
  }
}

async function check(response) {
  if (response.ok) return response.status === 204 ? {} : response.json();
  const body = await response.json().catch(() => ({})); // a proxy can return a non-JSON body
  throw new AvinaError(response.status, body);
}
```

One case needs extra care: a `409 idempotency_key_reused` when you retry a start with the same key and body means the first attempt is still being handled. Wait a few seconds and retry. See [Errors and retries](https://docs.data.avina.io/guides/errors-and-retries.md#when-you-do-not-know-if-a-search-started).

## Validation details

`400 invalid_request` reports every problem at once, so you can fix a request in one pass. The `field` is a path into the request body:

| `field` | Refers to |
| - | - |
| `limit` | A top-level body field |
| `filters.all.0` | The first condition in `filters.all` |
| `criteria.2` | The third item in `criteria` |
| `persona_ids` | The list of personas |
| `after` | A query parameter |
| `Idempotency-Key` | A header |

## Failures that are not errors

A search that was accepted and then ran into trouble does not return an HTTP error. The request that started it succeeded. Read the outcome from the search:

| Field | Value | Meaning |
| - | - | - |
| `status` | `failed` | The search could not finish. `error` has a message. Results found before the failure stay readable. |
| `stop_reason` | `query_needs_clarification` | The query could not be searched as written. `interpretation.unsupported_criteria` and `interpretation.errors` say why. Nothing was charged. |
| `stop_reason` | `usage_limit_reached` | The search reached `max_credits` or the workspace ran out of credits. |
| `stop_reason` | `provider_failed` | Every data source failed. A failed search can also have a `null` stop reason; read `error`. |

See [Search lifecycle](https://docs.data.avina.io/concepts/search-lifecycle.md#stop-reasons).

## Related

* [Errors and retries](https://docs.data.avina.io/guides/errors-and-retries.md): safe retry patterns with code


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.