> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.morphiaone.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.morphiaone.ai/_mcp/server.

# Error reference

Two things return an error code and a partner cannot tell them apart from the
outside, so both are listed here.

An **HTTP error** answers your request: a non-2xx status carrying
`error.code`. A **job error** is a submission we accepted that failed during
analysis; it arrives as HTTP `200` with `"status": "failed"` and a code in
`job.error.code`. Read a code together with where it came from, never on its
own.

Branch on the code. Each code has exactly one status and one fixed `message`,
and every error envelope also carries `doc_url`, a link to the code's row on
this page, and `retryable` -- see [Errors](/concepts/errors) for the envelope
and the reasoning.

## HTTP error codes (29)

`retryable: true` means: send the **same** request with the **same**
`Idempotency-Key` again, after `Retry-After` or with backoff -- see
[Retries and backoff](/concepts/retries). Every other code needs a change
before it can succeed.

| Code                          | Status | Retryable | Meaning                                                                                                 |
| ----------------------------- | ------ | --------- | ------------------------------------------------------------------------------------------------------- |
| `API_KEY_IP_NOT_ALLOWED`      | `403`  | no        | The API key is not allowed from this network.                                                           |
| `ASSET_CONTENT_UNAVAILABLE`   | `404`  | no        | The content of this asset is not available for download.                                                |
| `ASSET_EXPIRED`               | `410`  | no        | The referenced input asset has expired.                                                                 |
| `ASSET_NOT_FOUND`             | `404`  | no        | The asset was not found.                                                                                |
| `ASSET_OWNED_BY_JOB`          | `409`  | no        | A result asset is deleted together with its job. Delete the job instead.                                |
| `IDEMPOTENCY_IN_PROGRESS`     | `409`  | yes       | A request with this Idempotency-Key is still in progress. Retry after the Retry-After interval.         |
| `IDEMPOTENCY_KEY_REQUIRED`    | `400`  | no        | An Idempotency-Key header is required for this operation.                                               |
| `IDEMPOTENCY_KEY_REUSED`      | `409`  | no        | This Idempotency-Key was already used with a different request.                                         |
| `INSUFFICIENT_CREDITS`        | `402`  | no        | The account does not have enough credits for this job.                                                  |
| `INSUFFICIENT_SCOPE`          | `403`  | no        | The API key does not have the scope this operation requires.                                            |
| `INTERNAL_ERROR`              | `500`  | yes       | An unexpected error occurred. Quote the request id when contacting support.                             |
| `INVALID_API_KEY`             | `401`  | no        | The API key is invalid.                                                                                 |
| `INVALID_CURSOR`              | `400`  | no        | The cursor is invalid, or was issued for a different query.                                             |
| `INVALID_IDEMPOTENCY_KEY`     | `400`  | no        | The Idempotency-Key header must be 1 to 255 printable ASCII characters without spaces.                  |
| `INVALID_REQUEST`             | `400`  | no        | The request body failed validation.                                                                     |
| `INVALID_USAGE_RANGE`         | `400`  | no        | start\_date must be before end\_date, and the range cannot exceed 92 days.                              |
| `JOB_DELETED`                 | `410`  | no        | The job this Idempotency-Key created has been deleted.                                                  |
| `JOB_IN_PROGRESS`             | `409`  | no        | The job is still queued or running. Cancel it and wait for it to finish before deleting it.             |
| `JOB_NOT_CANCELLABLE`         | `409`  | no        | The job has already finished and cannot be cancelled.                                                   |
| `JOB_NOT_FOUND`               | `404`  | no        | The job was not found or has expired.                                                                   |
| `MAINTENANCE_MODE`            | `503`  | yes       | New jobs are paused for maintenance. Retry after the Retry-After interval.                              |
| `PAYLOAD_TOO_LARGE`           | `413`  | no        | The request body exceeds the maximum size.                                                              |
| `QUEUE_CAPACITY_EXCEEDED`     | `503`  | yes       | The service is at capacity. Retry after the Retry-After interval.                                       |
| `QUOTA_EXCEEDED`              | `429`  | no        | The daily job quota is exhausted. Do not retry before the quota resets.                                 |
| `RATE_LIMITED`                | `429`  | yes       | Too many requests. Retry after the Retry-After interval.                                                |
| `SERVICE_UNAVAILABLE`         | `503`  | yes       | A service this operation depends on is temporarily unavailable. Retry after the Retry-After interval.   |
| `TENANT_QUEUE_LIMIT_EXCEEDED` | `429`  | yes       | Too many of this account's jobs are waiting. Retry after the Retry-After interval.                      |
| `UNPROCESSABLE_IMAGE`         | `422`  | no        | The image cannot be processed: it exceeds the maximum width, height or pixel count, or does not decode. |
| `UNSUPPORTED_MEDIA_TYPE`      | `415`  | no        | The body is not an image/jpeg, image/png or image/webp image of the declared type.                      |

## Job error codes (3)

Delivered inside a `200` response, on a job whose `status` is `failed`:

| Code                  | What happened                                                                                                                      |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `INPUT_EXPIRED`       | The job's input snapshot expired before processing.                                                                                |
| `INPUT_UNPROCESSABLE` | The image could not be used for this operation (required subject not found, image quality too low, or image could not be decoded). |
| `PROCESSING_FAILED`   | Processing failed for a reason the caller cannot correct; retrying with a new Idempotency-Key may succeed.                         |

> **Warning**
>
> Nothing in your HTTP client raises on these. A `200` whose `status` is
> `failed` reaches code that assumed success unless you check `status` before
> reading `output` -- [Asynchronous jobs](/concepts/jobs).

## Handling an unfamiliar code

Adding a code is not a breaking change, so your integration will meet one it
does not know. Read its `retryable` field, and fall back to the status class
rather than crashing: treat an unrecognised `4xx` as your own fault and do not
retry it, an unrecognised `5xx` as ours and retry it with backoff, and an
unrecognised job error as a terminal failure of that job. Log the code and the
`request_id` so the gap is visible.

Renaming or removing a code *is* breaking; see
[Versioning](/concepts/versioning).