# Error catalog

Every error body is `{ error: { type, code, message, remediation, retryable, param?, docs_url, request_id } }`.
`type` and `code` are the **stable machine contract** — branch on those, never on `message`.
Each code below ships with a fixed `retryable` flag and a stable `docs_url` of the form `https://norano.app/docs/api/errors#<docsSlug>`.

## invalid_request

### `invalid_request`

- **HTTP status:** 400
- **Retryable:** no
- **Message:** The request was malformed.
- **Remediation:** Check the request shape against the API reference and resend.
- **docs_url:** https://norano.app/docs/api/errors#invalid_request

### `missing_param`

- **HTTP status:** 400
- **Retryable:** no
- **Message:** A required parameter is missing.
- **Remediation:** Add the missing parameter named in `param` and resend.
- **docs_url:** https://norano.app/docs/api/errors#missing_param

### `unsupported_media_type`

- **HTTP status:** 415
- **Retryable:** no
- **Message:** The request Content-Type is not supported by this endpoint.
- **Remediation:** Send the body with a supported Content-Type (e.g. application/json).
- **docs_url:** https://norano.app/docs/api/errors#unsupported_media_type

### `payload_too_large`

- **HTTP status:** 413
- **Retryable:** no
- **Message:** The request payload exceeds the allowed size.
- **Remediation:** Reduce the payload size, or use the signed-upload flow for large files.
- **docs_url:** https://norano.app/docs/api/errors#payload_too_large

### `method_not_allowed`

- **HTTP status:** 405
- **Retryable:** no
- **Message:** The HTTP method is not allowed on this resource.
- **Remediation:** Use one of the methods listed in the `Allow` response header.
- **docs_url:** https://norano.app/docs/api/errors#method_not_allowed

### `validation_error`

- **HTTP status:** 422
- **Retryable:** no
- **Message:** The request body failed validation.
- **Remediation:** Fix the field named in `param` (see `message`) and resend.
- **docs_url:** https://norano.app/docs/api/errors#validation_error

### `idempotency_key_reuse`

- **HTTP status:** 422
- **Retryable:** no
- **Message:** This Idempotency-Key was already used with a different request body.
- **Remediation:** Use a fresh Idempotency-Key for a request with a different body.
- **docs_url:** https://norano.app/docs/api/errors#idempotency_key_reuse

## authentication

### `missing_api_key`

- **HTTP status:** 401
- **Retryable:** no
- **Message:** No API key was provided.
- **Remediation:** Send your key as `Authorization: Bearer norano_sk_live_…` (or a test key).
- **docs_url:** https://norano.app/docs/api/errors#missing_api_key

### `invalid_api_key`

- **HTTP status:** 401
- **Retryable:** no
- **Message:** The provided API key is invalid.
- **Remediation:** Check the key value, or issue a new key, then resend.
- **docs_url:** https://norano.app/docs/api/errors#invalid_api_key

### `expired_api_key`

- **HTTP status:** 401
- **Retryable:** no
- **Message:** The provided API key has expired.
- **Remediation:** Issue a new key and resend.
- **docs_url:** https://norano.app/docs/api/errors#expired_api_key

## permission

### `insufficient_scope`

- **HTTP status:** 403
- **Retryable:** no
- **Message:** The API key lacks the scope required for this operation.
- **Remediation:** Use a key that holds the required scope, or grant the scope to this key.
- **docs_url:** https://norano.app/docs/api/errors#insufficient_scope

### `tenant_mismatch`

- **HTTP status:** 403
- **Retryable:** no
- **Message:** The requested resource belongs to a different tenant.
- **Remediation:** Use a key that belongs to the resource owner.
- **docs_url:** https://norano.app/docs/api/errors#tenant_mismatch

### `test_mode_resource_in_live`

- **HTTP status:** 403
- **Retryable:** no
- **Message:** A test-mode resource cannot be accessed with a live key (or vice versa).
- **Remediation:** Use a key whose mode (live/test) matches the resource.
- **docs_url:** https://norano.app/docs/api/errors#test_mode_resource_in_live

## not_found

### `resource_not_found`

- **HTTP status:** 404
- **Retryable:** no
- **Message:** The requested resource was not found.
- **Remediation:** Check the id and that the resource belongs to your tenant.
- **docs_url:** https://norano.app/docs/api/errors#resource_not_found

## conflict

### `idempotency_in_progress`

- **HTTP status:** 409
- **Retryable:** yes
- **Message:** A request with this Idempotency-Key is still being processed.
- **Remediation:** Wait briefly and retry with the same Idempotency-Key.
- **docs_url:** https://norano.app/docs/api/errors#idempotency_in_progress

### `plan_not_ready`

- **HTTP status:** 409
- **Retryable:** yes
- **Message:** The plan is still parsing; it cannot be used yet.
- **Remediation:** Poll the plan's parse Job until it succeeds, then retry.
- **docs_url:** https://norano.app/docs/api/errors#plan_not_ready

### `source_not_ready`

- **HTTP status:** 409
- **Retryable:** yes
- **Message:** A source resource this operation depends on is not ready yet.
- **Remediation:** Wait for the source to become ready, then retry.
- **docs_url:** https://norano.app/docs/api/errors#source_not_ready

## rate_limit

### `rate_limited`

- **HTTP status:** 429
- **Retryable:** yes
- **Message:** Too many requests.
- **Remediation:** Wait for the duration in the `Retry-After` header, then retry.
- **docs_url:** https://norano.app/docs/api/errors#rate_limited

## budget

### `budget_exceeded`

- **HTTP status:** 402
- **Retryable:** no
- **Message:** This key's spend cap has been reached.
- **Remediation:** Raise this key's cap or use a different key.
- **docs_url:** https://norano.app/docs/api/errors#budget_exceeded

### `quota_exceeded`

- **HTTP status:** 402
- **Retryable:** no
- **Message:** A usage quota has been exceeded.
- **Remediation:** Wait for the quota to reset, raise the quota, or use a different key.
- **docs_url:** https://norano.app/docs/api/errors#quota_exceeded

## provider

### `provider_unavailable`

- **HTTP status:** 502
- **Retryable:** yes
- **Message:** An upstream generation provider is currently unavailable.
- **Remediation:** Retry after a short backoff; the provider may be temporarily down.
- **docs_url:** https://norano.app/docs/api/errors#provider_unavailable

## job

### `job_failed`

- **HTTP status:** 409
- **Retryable:** no
- **Message:** The job failed.
- **Remediation:** Inspect the job's `error` object for the specific failure and remedy.
- **docs_url:** https://norano.app/docs/api/errors#job_failed

## server

### `internal_error`

- **HTTP status:** 500
- **Retryable:** yes
- **Message:** An unexpected error occurred.
- **Remediation:** Retry after a short backoff. If it persists, contact support.
- **docs_url:** https://norano.app/docs/api/errors#internal_error

### `service_unavailable`

- **HTTP status:** 503
- **Retryable:** yes
- **Message:** A required dependency is temporarily unavailable, so the request was not processed.
- **Remediation:** Retry after a short backoff. The request was rejected without being processed, so retrying is safe.
- **docs_url:** https://norano.app/docs/api/errors#service_unavailable
