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

# Errors

> Error codes you may encounter and how to handle them.

Errors follow [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) and
are served with `Content-Type: application/problem+json`:

```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json

{
  "type":     "https://errors.attestly.io/quota-exceeded",
  "title":    "Quota Exceeded",
  "status":   429,
  "detail":   "Monthly quota of 10000 requests exceeded for this billing period.",
  "instance": "/v1/evaluate",
  "quota": {
    "limit": 10000,
    "used":  10000,
    "period_started_at": "2026-04-15T00:00:00Z",
    "period_ends_at":   "2026-05-15T00:00:00Z"
  }
}
```

Match against the `type` URI — it is stable across releases and
dereferenceable to documentation. `title` and `detail` are
human-readable and may be reworded; do not switch on them.

Some problem types carry **extension members** (the `quota` block
above is one). The base members (`type`, `title`, `status`, `detail`,
`instance`) are always present; extensions are documented per error
type below.

## Authentication & access

| Status | Type URI                                           | When                                                |
| ------ | -------------------------------------------------- | --------------------------------------------------- |
| 401    | `https://errors.attestly.io/authentication-failed` | Missing, malformed, or revoked API key.             |
| 402    | `https://errors.attestly.io/subscription-inactive` | Subscription is no longer active.                   |
| 429    | `https://errors.attestly.io/quota-exceeded`        | Monthly cap reached for the current billing period. |
| 429    | `https://errors.attestly.io/rate-limit-exceeded`   | Too many requests in a short window.                |

429 responses carry `Retry-After` and `X-RateLimit-*` headers. The
`quota-exceeded` type additionally carries a `quota` extension with
`limit`, `used`, `period_started_at`, `period_ends_at`. See
[Quotas](/reference/quotas).

## Validation

| Status | Type URI                                                | When                                               |
| ------ | ------------------------------------------------------- | -------------------------------------------------- |
| 422    | `https://errors.attestly.io/request-validation-failed`  | Bad JSON, wrong types, missing required fields.    |
| 422    | `https://errors.attestly.io/program-validation-failed`  | Ruleset structure invalid (depth, refs, ceilings). |
| 422    | `https://errors.attestly.io/program-compilation-failed` | Ruleset references could not be compiled.          |
| 422    | `https://errors.attestly.io/unknown-source`             | Ruleset references a source you can't access.      |

## Catalog

| Status | Type URI                                            | When                             |
| ------ | --------------------------------------------------- | -------------------------------- |
| 404    | `https://errors.attestly.io/ruleset-not-found`      | `ruleset_id` doesn't resolve.    |
| 409    | `https://errors.attestly.io/ruleset-already-exists` | `(name, version)` already taken. |

## Idempotency

| Status | Type URI                                                | When                                            |
| ------ | ------------------------------------------------------- | ----------------------------------------------- |
| 422    | `https://errors.attestly.io/idempotency-key-invalid`    | Malformed `Idempotency-Key` header.             |
| 422    | `https://errors.attestly.io/idempotency-key-conflict`   | Same key, different request body.               |
| 429    | `https://errors.attestly.io/idempotency-key-exhausted`  | Too many concurrent requests with the same key. |
| 410    | `https://errors.attestly.io/idempotency-replay-expired` | Replay window for that key has elapsed.         |

## Server (5xx)

| Status | Type URI                                          | When                            |
| ------ | ------------------------------------------------- | ------------------------------- |
| 500    | `https://errors.attestly.io/internal-error`       | Unexpected server error.        |
| 503    | `https://errors.attestly.io/database-unavailable` | Transient infrastructure issue. |

5xx responses are retryable. Use exponential backoff with jitter; if
persistent, contact `support@attestly.io`.

## Partial failures (200)

A source or check failure does not fail the whole request. The
response is `200` but `verdict.status = "degraded"` and the affected
check carries `status: "failed"` with an `error` message. See
[Verdicts](/concepts/verdicts).
