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

# Error Codes

> Complete reference for every error status code returned by the Avala API, with descriptions, common causes, and remediation steps.

When a request fails, the Avala API returns an appropriate HTTP status code along with a JSON body describing the error. Use the status code to determine the category of failure and the response body for specifics.

## Standard Error Response

Most errors return a JSON object with a `detail` field:

```json theme={null}
{
  "detail": "A human-readable description of the error."
}
```

Some endpoints return structured errors with a machine-readable `code` and a link to the relevant documentation:

```json theme={null}
{
  "detail": "Project approval requires a PRO or ENTERPRISE plan.",
  "code": "plan_insufficient",
  "doc_url": "https://docs.avala.ai/api/errors#plan_insufficient"
}
```

Use the `code` field for programmatic error handling in your pipeline. The `detail` field is human-readable and may change between versions.

## Validation Errors

Requests that fail input validation return a `400` status code with field-specific error details:

```json theme={null}
{
  "detail": {
    "name": ["This field is required."],
    "email": ["Enter a valid email address."]
  }
}
```

Each key corresponds to a request field, and the value is an array of error messages for that field.

## Error Code Reference

| Status Code | Name                  | Description                                                                          |
| ----------- | --------------------- | ------------------------------------------------------------------------------------ |
| `400`       | Bad Request           | The request body is invalid, malformed, or missing required fields.                  |
| `401`       | Unauthorized          | Authentication failed — the API key is missing, invalid, or expired.                 |
| `403`       | Forbidden             | The authenticated key does not have permission to perform this action.               |
| `404`       | Not Found             | The requested resource does not exist or has been deleted.                           |
| `405`       | Method Not Allowed    | The HTTP method is not supported for this endpoint.                                  |
| `409`       | Conflict              | The request conflicts with the current state of the resource (e.g., duplicate name). |
| `413`       | Payload Too Large     | The request body exceeds the maximum allowed size.                                   |
| `429`       | Too Many Requests     | Rate limit exceeded. Back off and retry after the window resets.                     |
| `500`       | Internal Server Error | An unexpected error occurred on the server.                                          |
| `503`       | Service Unavailable   | The API is temporarily offline for maintenance or under heavy load.                  |

## Detailed Error Descriptions

### 400 — Bad Request

The request is malformed or contains invalid data.

**Common causes:**

* Missing a required field in the request body
* Sending an invalid data type (e.g., string where an integer is expected)
* Malformed JSON in the request body

```json theme={null}
{
  "detail": {
    "name": ["This field is required."],
    "schedule": ["Invalid cron expression."]
  }
}
```

**Remediation:** Check the request body against the endpoint's schema. Ensure all required fields are present and correctly typed.

***

### 401 — Unauthorized

Authentication failed.

**Common causes:**

* No `X-Avala-Api-Key` header included in the request
* The API key is invalid or has been revoked
* The API key has expired

```json theme={null}
{
  "detail": "Invalid API key."
}
```

**Remediation:** Verify your API key is correct and active. Generate a new key from [Mission Control](https://avala.ai) if needed. See [Authentication](/docs/api-reference/authentication).

***

### 403 — Forbidden

The API key is valid but lacks permission for the requested action.

**Common causes:**

* Attempting to access a resource owned by a different organization
* Insufficient role or permission level for the operation
* API key is missing a required scope
* Organization plan does not include the requested feature

```json theme={null}
{
  "detail": "You do not have permission to perform this action."
}
```

**Remediation:** Confirm the resource belongs to your organization. Contact your team admin if you need elevated permissions.

#### Structured Error Codes

Some 403 responses include a machine-readable `code` for programmatic handling:

<a id="plan_insufficient" />

**`plan_insufficient`** — Your organization's plan does not support this action. Upgrade to PRO or ENTERPRISE to access this feature.

```json theme={null}
{
  "detail": "Project approval requires a PRO or ENTERPRISE plan.",
  "code": "plan_insufficient",
  "doc_url": "https://docs.avala.ai/api/errors#plan_insufficient"
}
```

**Remediation:** Contact your Avala account manager to upgrade your organization's plan.

<a id="scope_required" />

**`scope_required`** — Your API key does not include the required scope for this action.

```json theme={null}
{
  "detail": "API key requires 'projects.write' scope.",
  "code": "scope_required",
  "doc_url": "https://docs.avala.ai/api/errors#scope_required"
}
```

**Remediation:** Create a new API key with the required scope from [Settings > Security](https://avala.ai/settings?section=security) in Mission Control. See [API Key Scopes](/docs/api-reference/authentication#api-key-scopes) for the full list.

***

### 404 — Not Found

The requested resource does not exist.

**Common causes:**

* The resource ID is incorrect or misspelled
* The resource was previously deleted
* The URL path is wrong

```json theme={null}
{
  "detail": "Not found."
}
```

**Remediation:** Verify the resource ID and endpoint path. List resources to confirm the ID exists.

***

### 405 — Method Not Allowed

The HTTP method is not supported on the endpoint.

**Common causes:**

* Sending a `PATCH` request to an endpoint that only supports `GET` and `POST`
* Using `DELETE` on a resource that does not support deletion

```json theme={null}
{
  "detail": "Method \"PATCH\" not allowed."
}
```

**Remediation:** Check the [API reference](/docs/api-reference/overview) for the supported methods on the endpoint.

***

### 409 — Conflict

The request conflicts with the current state of a resource.

**Common causes:**

* Creating a resource with a name that already exists
* Attempting a state transition that is not allowed (e.g., re-activating a completed run)

```json theme={null}
{
  "detail": "An agent with this name already exists."
}
```

**Remediation:** Change the conflicting field value, or fetch the existing resource and update it instead.

***

### 413 — Payload Too Large

The request body exceeds the maximum allowed size.

**Common causes:**

* Uploading a file that exceeds the size limit
* Sending an excessively large JSON payload

```json theme={null}
{
  "detail": "Request body too large. Maximum size is 100MB."
}
```

**Remediation:** Reduce the payload size. For file uploads, compress the file or split it into smaller parts.

***

### 429 — Too Many Requests

You have exceeded the rate limit.

**Common causes:**

* Sending more than 100 requests per minute
* Exceeding concurrent upload or export limits

```json theme={null}
{
  "detail": "Request was throttled. Expected available in 12 seconds."
}
```

The response includes rate limit headers:

| Header                  | Description                                    |
| ----------------------- | ---------------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed in the current window |
| `X-RateLimit-Remaining` | Requests remaining in the current window       |
| `X-RateLimit-Reset`     | Unix timestamp when the window resets          |

**Remediation:** Wait until the rate limit window resets, then retry. Implement exponential backoff in your client.

***

### 500 — Internal Server Error

An unexpected error occurred on the server.

**Common causes:**

* A bug or transient failure in the Avala backend

```json theme={null}
{
  "detail": "Internal server error."
}
```

**Remediation:** Retry the request after a brief delay. If the error persists, contact [support@avala.ai](mailto:support@avala.ai) with the request details.

***

### 503 — Service Unavailable

The API is temporarily unable to handle requests.

**Common causes:**

* Scheduled maintenance
* The service is under heavy load

```json theme={null}
{
  "detail": "Service temporarily unavailable. Please try again later."
}
```

**Remediation:** Wait and retry with exponential backoff. Check the [Avala status page](https://status.avala.ai) for incident updates.

## Handling Errors

Implement retry logic with exponential backoff for transient errors (`429`, `500`, `503`). Do not retry client errors (`400`, `401`, `403`, `404`).

```python Python theme={null}
import time
import requests

def request_with_retry(method, url, headers, json=None, max_retries=3):
    """Make an API request with exponential backoff for transient errors."""
    retryable_status_codes = {429, 500, 503}

    for attempt in range(max_retries + 1):
        response = requests.request(
            method, url, headers=headers, json=json
        )

        if response.status_code not in retryable_status_codes:
            return response

        if attempt == max_retries:
            return response

        # Use Retry-After or X-RateLimit-Reset if available
        retry_after = response.headers.get("Retry-After")
        if retry_after:
            wait = int(retry_after)
        else:
            wait = 2 ** attempt  # 1s, 2s, 4s

        print(f"Request failed with {response.status_code}. "
              f"Retrying in {wait}s (attempt {attempt + 1}/{max_retries})...")
        time.sleep(wait)

    return response


# Usage
response = request_with_retry(
    method="GET",
    url="https://api.avala.ai/api/v1/datasets/",
    headers={"X-Avala-Api-Key": "avk_your_api_key"},
)

if response.ok:
    data = response.json()
else:
    print(f"Error {response.status_code}: {response.json()['detail']}")
```

### Handling Structured Error Codes

Some endpoints return structured errors with a `code` field for programmatic handling. Use the `code` to take specific actions in your pipeline:

```python theme={null}
response = requests.post(
    f"https://api.avala.ai/api/v1/projects/{project_uid}/approve/",
    headers={"X-Avala-Api-Key": API_KEY},
)

if response.ok:
    project = response.json()
    print(f"Approved: {project['name']}")
else:
    error = response.json()
    code = error.get("code")

    if code == "plan_insufficient":
        # Organization needs a plan upgrade
        notify_ops("Plan upgrade needed for project approval")
    elif code == "scope_required":
        # API key is missing a required scope
        notify_ops(f"API key needs scope: {error['detail']}")
    elif response.status_code == 400:
        # Invalid state transition (e.g., project already active)
        log.warning(f"Cannot approve: {error['detail']}")
    elif response.status_code == 404:
        # Project not found or not owned by this user
        log.error(f"Project {project_uid} not found")
```

### Error Recovery Decision Tree

```
API call fails
  |
  +-- 401 Unauthorized
  |     -> API key invalid or expired. Rotate key. Do NOT retry.
  |
  +-- 403 Forbidden
  |     +-- code: "plan_insufficient" -> Upgrade org plan. Do NOT retry.
  |     +-- code: "scope_required"    -> Create new key with scope. Do NOT retry.
  |     +-- (no code)                 -> Wrong owner/org. Do NOT retry.
  |
  +-- 404 Not Found
  |     -> Check resource UID. Do NOT retry.
  |
  +-- 400 Bad Request
  |     -> Fix request body or check resource state. Do NOT retry.
  |
  +-- 429 Too Many Requests
  |     -> Wait for Retry-After header, then retry.
  |
  +-- 500 / 503
        -> Retry with exponential backoff (1s, 2s, 4s).
```
