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

# Error Handling

> Understanding and handling API errors

The Archetype AI APIs use conventional HTTP response codes to indicate success or failure, and return a structured JSON body for every error. This page describes the response shape, how to map HTTP status codes to outcomes, and patterns for retrying transient errors.

For the canonical list of error `code` values, see [Error Codes](/support/error-codes).

## Error response format

Most endpoints (Files, Batch Processing, Query, and the data-plane services) return errors in a **plural `errors` array** envelope:

```json theme={"system"}
{
  "errors": [
    {
      "code": "invalid_file_type",
      "message": "Unsupported file type: application/octet-stream",
      "suggestion": "Supported types: image/jpeg, image/png, video/mp4, text/csv, text/plain, application/json",
      "error_uid": "err-bfa600db-c703-4061-ad9c-c14628b3554c"
    }
  ]
}
```

<ResponseField name="errors[].code" type="string">
  Machine-readable error code for programmatic handling. See [Error Codes](/support/error-codes) for the canonical list. Codes are typically lowercase snake\_case (e.g. `invalid_file_type`, `upload_not_found`), though a few legacy endpoints emit uppercase (e.g. `NOT_FOUND`).
</ResponseField>

<ResponseField name="errors[].message" type="string">
  Human-readable description of what went wrong.
</ResponseField>

<ResponseField name="errors[].suggestion" type="string">
  Optional hint for how to resolve or mitigate the error.
</ResponseField>

<ResponseField name="errors[].error_uid" type="string">
  Per-error UUID prefixed with `err-`. Include this when reporting issues to support — it lets the platform team find the corresponding server logs.
</ResponseField>

A response may carry **more than one error** in the array (for example, a request with both a missing parameter and an invalid value). Always iterate the array rather than reading `errors[0]` exclusively.

<Note>
  **Legacy envelope:** A handful of older endpoints (notably some authentication failures) still return the FastAPI-style envelope `{"detail": "<message>"}` with no `errors` array, `error_uid`, or `suggestion`. Treat any 4xx/5xx response with neither `errors` nor `detail` as an unknown shape and log the raw body.
</Note>

## HTTP Status Codes

<AccordionGroup>
  <Accordion title="2xx Success">
    <ResponseField name="200" type="OK">
      Request succeeded
    </ResponseField>

    <ResponseField name="201" type="Created">
      Resource successfully created
    </ResponseField>

    <ResponseField name="204" type="No Content">
      Request succeeded, no content to return
    </ResponseField>
  </Accordion>

  <Accordion title="4xx Client Errors">
    <ResponseField name="400" type="Bad Request">
      Invalid request parameters or malformed request body
    </ResponseField>

    <ResponseField name="401" type="Unauthorized">
      Missing or invalid API key
    </ResponseField>

    <ResponseField name="403" type="Forbidden">
      Valid credentials but insufficient permissions
    </ResponseField>

    <ResponseField name="404" type="Not Found">
      Requested resource does not exist
    </ResponseField>

    <ResponseField name="409" type="Conflict">
      Request conflicts with current state (e.g. cancelling a job that already completed, completing an upload that's already completed)
    </ResponseField>

    <ResponseField name="413" type="Payload Too Large">
      Request body exceeds size limits. For `POST /v0.5/files` this is 512 MB; for larger uploads use the [multipart presigned flow](/api-reference/files/initiate-upload) (up to 250 GB).
    </ResponseField>

    <ResponseField name="429" type="Too Many Requests">
      Rate limit exceeded
    </ResponseField>
  </Accordion>

  <Accordion title="5xx Server Errors">
    <ResponseField name="500" type="Internal Server Error">
      Unexpected server error. Include the `error_uid` from the response body when reporting.
    </ResponseField>

    <ResponseField name="502" type="Bad Gateway">
      Gateway or proxy error.
    </ResponseField>

    <ResponseField name="503" type="Service Unavailable">
      Server temporarily at capacity; retry with backoff. If uploading multiple large
      files at once (or a large number of small ones), this may be due to too many
      concurrent uploads or the server's memory budget being exceeded. Wait a suitable backoff period
      and try the upload again.
    </ResponseField>

    <ResponseField name="504" type="Gateway Timeout">
      Upstream service timeout.
    </ResponseField>
  </Accordion>
</AccordionGroup>

## Error codes

The canonical list of error codes lives on [Error Codes](/support/error-codes). Each entry there describes the code, the meaning, and which API surface (Files, Lens, Batch, etc.) emits it.

Common patterns you'll see in practice:

* **`invalid_*`** — request validation failed (`invalid_file_type`, `invalid_upload_parts`, `invalid_request`). The `message` and `suggestion` together tell you which field is wrong.
* **`*_not_found`** — the resource doesn't exist or has been deleted (`upload_not_found`, `file_not_found`, `NOT_FOUND` for some legacy batch endpoints). Verify the id and that the resource hasn't been cleaned up.
* **`*_already_completed` / state conflicts** — a 409 telling you the target is already in a terminal state. Often safe to treat as success in idempotent client code (e.g. cancelling an already-cancelled job).
* **`unauthorized_request`** — bad or missing bearer token. Verify the `Authorization: Bearer <key>` header.
* **`capacity_reached`, `server_at_capacity`** — back-pressure from the server. Retry with exponential backoff.

## Retry Strategies

Retry transient failures (`429`, `500`, `502`, `503`, `504`) with **exponential backoff plus
jitter**. Don't retry other 4xx responses — they indicate a client-side problem (bad request,
missing resource, conflict) that won't change by waiting.

```python theme={"system"}
import time
import random
import requests

TRANSIENT_STATUSES = {429, 500, 502, 503, 504}

def make_request_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.ok:
            return response.json()

        # Pull whatever identifying info we can out of the body. Most endpoints
        # use the plural `errors` array; some legacy paths use `{"detail": ...}`.
        code = None
        error_uid = None
        try:
            body = response.json()
            if isinstance(body.get("errors"), list) and body["errors"]:
                code = body["errors"][0].get("code")
                error_uid = body["errors"][0].get("error_uid")
            elif "detail" in body:
                code = "detail"  # legacy envelope
        except ValueError:
            pass

        if response.status_code not in TRANSIENT_STATUSES:
            # 4xx other than 429 — don't retry, surface the error.
            response.raise_for_status()

        wait_time = (2 ** attempt) + random.uniform(0, 1)
        print(
            f"Transient {response.status_code} (code={code}, "
            f"error_uid={error_uid}). Retrying in {wait_time:.2f}s..."
        )
        time.sleep(wait_time)

    raise Exception(f"Max retries ({max_retries}) exceeded")

# Usage
try:
    data = make_request_with_retry(
        "https://api.u1.archetypeai.app/v0.5/lens/info",
        {"Authorization": "Bearer YOUR_API_KEY"},
    )
    print(data)
except Exception as e:
    print(f"Request failed after retries: {e}")
```

<Note>
  Rate limiting today is scoped to the login endpoint and returns the legacy `{"detail": "Too many login attempts. Please try again in N minutes."}` envelope without a `Retry-After` header. Other Newton endpoints do not currently rate-limit at the API surface, so 429s on those paths are not expected.
</Note>

## Error logging

When you log API errors, capture the **status code**, the primary `error_uid`, and the request URL — `error_uid` is the field that lets the platform team correlate your report to server logs.

* Iterate the full `errors` array, not just `errors[0]` — multi-error responses do occur.
* Log the raw response body when JSON parsing fails (gateway / proxy errors can return HTML).
* Include the request method and URL so a single log line is enough context to reproduce.

```python theme={"system"}
import logging
import requests

logger = logging.getLogger(__name__)

def log_api_error(response: requests.Response, method: str, url: str) -> None:
    try:
        body = response.json()
        errors = body.get("errors") or []
    except ValueError:
        body, errors = None, []

    primary = errors[0] if errors else {}
    logger.error(
        "Newton API error",
        extra={
            "status_code": response.status_code,
            "error_code": primary.get("code"),
            "error_uid": primary.get("error_uid"),
            "request_method": method,
            "request_url": url,
            "response_body": body if body is not None else response.text,
        },
    )

# Usage
response = requests.get(url, headers=headers)
if not response.ok:
    log_api_error(response, "GET", url)
    response.raise_for_status()
```

## Getting help

<CardGroup cols={2}>
  <Card title="Check API Status" icon="chart-line" href="https://status.archetypeai.app/">
    View current system status and incidents
  </Card>

  <Card title="Contact Support" icon="headset" href="mailto:support@archetypeai.dev">
    Get help from our technical support team at [support@archetypeai.dev](mailto:support@archetypeai.dev)
  </Card>
</CardGroup>

When contacting support, please include:

* The `error_uid` from the response body
* The HTTP status code and the full `errors` array
* The request URL, method, and (sanitized) headers
* Timestamp of the failed request
* Your organization ID
* Minimal steps to reproduce
