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

# Error handling

> Use status codes, problem details, and request IDs to handle Canary API failures

# Error handling

Canary errors use `application/problem+json`. The body follows Problem Details and adds a machine-readable `code`, `request_id`, and optional field errors.

```json theme={"theme":"github-light"}
{
  "type": "https://api.oncanary.com/errors/validation_error",
  "title": "Validation Error",
  "status": 400,
  "detail": "Request validation failed",
  "request_id": "req_01JAY8FVDM6CH4R3X9Q2T7K5NP",
  "code": "validation_error",
  "validation_errors": [
    {
      "field": "title",
      "message": "Required"
    }
  ]
}
```

## Response fields

| Field               | Meaning                                 |
| ------------------- | --------------------------------------- |
| `type`              | Stable URI for the error family         |
| `title`             | Short human-readable category           |
| `status`            | HTTP status repeated in the body        |
| `detail`            | Context for this occurrence             |
| `request_id`        | Correlation ID matching `X-Request-ID`  |
| `code`              | Value to branch on in application logic |
| `validation_errors` | Optional field-level validation details |

Use `status` for the broad recovery path and `code` for a specific branch. Keep `detail` for logs and people.

## Status codes

|                       Status | Meaning                                                       | Client action                                   |
| ---------------------------: | ------------------------------------------------------------- | ----------------------------------------------- |
|            `400 Bad Request` | Invalid query, cursor, JSON, field, filename, or empty upload | Correct the request                             |
|           `401 Unauthorized` | Missing, malformed, expired, or revoked API key               | Replace or restore the key                      |
|              `403 Forbidden` | Missing scope or disabled organization module                 | Change key scopes or organization configuration |
|              `404 Not Found` | Resource or related ID is unavailable to this organization    | Reconcile IDs and tenancy                       |
|               `409 Conflict` | Lifecycle, hierarchy, dependency, or uniqueness conflict      | Read current state and resolve the conflict     |
|      `413 Content Too Large` | Work-request upload exceeds 1 MiB                             | Reduce file size                                |
| `415 Unsupported Media Type` | Thumbnail content type or image bytes are unsupported         | Send a supported image                          |
|      `429 Too Many Requests` | API-key budget is depleted                                    | Wait for `Retry-After`                          |
|  `500 Internal Server Error` | Unexpected server failure                                     | Retry with backoff and retain the request ID    |

## Common codes

| Code                          | Status | Typical cause                                              |
| ----------------------------- | -----: | ---------------------------------------------------------- |
| `validation_error`            |    400 | One or more parsed fields failed validation                |
| `invalid_request`             |    400 | Malformed JSON or request body                             |
| `invalid_cursor`              |    400 | Cursor is malformed or belongs to another pagination shape |
| `invalid_file_name`           |    400 | Upload filename is empty, unsafe, or too long              |
| `empty_upload`                |    400 | Upload body has zero bytes                                 |
| `missing_authorization`       |    401 | Authorization header is absent                             |
| `invalid_api_key`             |    401 | Key is unknown, expired, or revoked                        |
| `insufficient_scope`          |    403 | Key lacks the operation's `x-required-scope`               |
| `module_disabled`             |    403 | Required Canary module is disabled for the organization    |
| `not_found`                   |    404 | Resource or referenced relation is unavailable             |
| `identifier_conflict`         |    409 | Identifier payload or primary assignment conflicts         |
| `custom_field_label_conflict` |    409 | Active definition already uses the label                   |
| `invalid_location_hierarchy`  |    409 | Requested parent relationship breaks hierarchy rules       |
| `invalid_work_request_state`  |    409 | Request state blocks approval or attachment changes        |
| `resource_in_use`             |    409 | An automation depends on the meter                         |
| `payload_too_large`           |    413 | Upload exceeds 1 MiB                                       |
| `invalid_picture`             |    415 | Thumbnail data cannot be decoded as an accepted image      |
| `rate_limit_exceeded`         |    429 | API-key budget is depleted                                 |

## Request IDs

Every public API response includes `X-Request-ID`, including `204 No Content` and authentication failures.

```javascript theme={"theme":"github-light"}
const response = await fetch(url, options);
const requestId = response.headers.get('X-Request-ID');

if (!response.ok) {
  const problem = await response.json();
  console.error({ requestId, code: problem.code, detail: problem.detail });
}
```

A `204` response body has no request ID because it has no body; read `X-Request-ID` from the header. Include this value when contacting support.

## Retry policy

* Retry `429` after the number of seconds in `Retry-After`.
* Retry transient `500` responses with exponential backoff and jitter.
* Retry connection failures only when the operation's write semantics are safe for duplication.
* Handle `400`, `401`, `403`, `404`, `409`, `413`, and `415` through configuration or request correction.

See [Integration patterns](/guides/integration-patterns#write-retries-and-idempotency) for write safety.
