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

# Errors

> The error envelope and the stable list of error codes.

## Error envelope

Every error has the same shape:

```json theme={null}
{
  "error": {
    "code": "insufficient_credits",
    "message": "…",
    "request_id": "req_…",
    "retryable": false,
    "retry_after_seconds": null,
    "details": { "required": "94.50", "available": "40.00", "currency": "CREDITS" }
  }
}
```

| Field | Meaning |
| - | - |
| `code` | Stable, machine-readable code from the table below. Branch on this, never on `message`. |
| `message` | Human-readable explanation. It may change. |
| `request_id` | Same as the `X-Request-Id` header. Include it when you contact support. |
| `retryable` | Whether the same request can succeed later. |
| `retry_after_seconds` | When set, wait this long before retrying. The `Retry-After` header carries the same value. |
| `details` | Extra data for some codes, such as validation errors under `details.errors` or the amounts above. |

## Error codes

| HTTP | `code` | Retryable | Meaning |
| - | - | - | - |
| 400 | `bad_request` | No | The body is not valid JSON, or a header such as `Idempotency-Key` is malformed |
| 400 | `invalid_input` | No | A field failed validation; see `details.errors` |
| 400 | `unknown_parameter` | No | — |
| 401 | `unauthorized` | No | Missing, revoked or unknown key, or an invalid upload ticket |
| 401 | `session_not_accepted` | No | — |
| 402 | `insufficient_credits` | No | The balance does not cover the estimate. Top up, then retry |
| 403 | `forbidden` | No | The caller cannot act in this workspace |
| 403 | `spending_disabled` | No | Spending is turned off for this caller |
| 403 | `monthly_cap_exceeded` | No | The monthly spending cap is reached |
| 403 | `api_key_spend_limit_exceeded` | No | The key's spend limit is reached |
| 403 | `insufficient_scope` | No | The key lacks the scope; `details.required` names it |
| 403 | `plan_required` | No | The workspace's plan does not include this |
| 404 | `not_found` | No | No such job, run or resource, or you cannot read it |
| 404 | `model_not_found` | No | No such model, or it is not offered to this caller |
| 404 | `workspace_not_found` | No | The workspace does not exist or the key is not pinned to it |
| 408 | `request_timeout` | Yes | The request took too long |
| 409 | `conflict` | No | The request conflicts with the current state |
| 409 | `idempotency_conflict` | No | The `Idempotency-Key` was used with a different body |
| 409 | `model_price_unavailable` | No | The model has no usable price right now |
| 409 | `job_not_cancelable` | No | Only `queued` jobs can be canceled |
| 412 | `precondition_failed` | No | A precondition of the request is not met |
| 413 | `payload_too_large` | No | The declared upload size is over the limit |
| 415 | `unsupported_media_type` | No | The upload's content type is not accepted |
| 422 | `input_media_unreadable` | No | A media input could not be fetched, was over the limit, or could not be read |
| 429 | `queue_full` | Yes | The workspace queue is full |
| 429 | `concurrency_limit` | Yes | Too many jobs are running |
| 429 | `rate_limited` | Yes | Too many requests |
| 500 | `internal_error` | Yes | Unexpected error on Blon's side |
| 501 | `not_implemented` | No | Not supported |
| 502 | `provider_submission_failed` | No | The provider rejected the submission |
| 503 | `provider_capacity_exceeded` | Yes | The provider is at capacity |
| 503 | `provider_unavailable` | Yes | The provider is unavailable |
| 503 | `model_disabled` | Yes | The model is temporarily stopped |
| 503 | `service_unavailable` | Yes | Blon is temporarily unavailable |

Refusals at submission (`402`, `403`, `429`) are not charged.

## Retrying

Retry only when `retryable` is `true`. Wait `retry_after_seconds` when it is set, otherwise back off exponentially. When retrying `POST /jobs`, send the same `Idempotency-Key` so the retry cannot create a second job.

## Job errors

A job that fails after it was accepted is not an HTTP error: `GET /jobs/{id}` returns `200` with `status: "failed"` and an `error` object.

```json theme={null}
{ "code": "provider_unavailable", "message": "…", "retryable": true }
```

| `error.code` | Meaning |
| - | - |
| `content_policy` | The provider refused the content |
| `invalid_input` | The provider rejected an input |
| `rate_limited` | The provider was rate limited |
| `provider_unavailable` | The provider was unavailable |
| `timeout` | The job ran past the model's time limit |
| `unknown` | Any other failure |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.