# Error catalog

Every error is machine-readable and self-resolving:

```json
{ "error": { "code": "page_count_out_of_range", "message": "PDF has 12 pages; storybook supports 20-60.", "resolution": "Add at least 8 more pages." } }
```

REST uses HTTP status + this envelope. MCP returns the same object with `isError: true`.

| Code | Meaning | Fix |
|---|---|---|
| `not_a_pdf` | File isn't a PDF | Upload a real PDF |
| `corrupt_pdf` / `page_render_failed` | PDF or a page fails to parse | Re-export the PDF |
| `encrypted_pdf` | Password-protected | Remove the password |
| `file_too_large` | > 100 MB | Compress images |
| `page_count_out_of_range` | Outside 20–60 pages (storybook) / not exactly 1 page (sticker-a3) / not exactly 2 pages (greeting-card-a5) | Adjust page count |
| `inconsistent_page_size` | Pages differ in size | Re-export at one trim size |
| `unsupported_trim_size` | Not 8×8 in or A5 (storybook) / not A3 portrait (sticker-a3) / not 303×216 mm (greeting-card-a5), ±2 mm | Re-export at a supported trim |
| `upload_not_found` / `upload_not_received` | Bad or unused upload_id | create_upload, PUT the file, retry |
| `upload_url_expired` / `invalid_upload_url` | Signed URL stale/altered | create_upload again, use put_url verbatim |
| `pdf_not_printable` | Validation errors exist | Fix listed issues, upload again |
| `invalid_fields` / `invalid_field` | Bad request field(s) | Fix fields named in details |
| `order_not_found` | Unknown order_id | Check the id from create_order |
| `not_order_owner` | Missing/wrong order_token | Pass the token from create_order |
| `not_cancellable` / `invalid_transition` | Status doesn't allow it for this caller, or the order moved before the cancel landed | awaiting_payment for anyone; confirmed/printing for the creating API key only. The message names the status the order is actually in — read it and retry only if that status is still cancellable |
| `too_many_codes` | OTP rate limit | Wait up to an hour |
| `rate_limited` (429) | Too many keyless `create_upload` calls, or too many unused uploads open, from one origin | Honour `Retry-After`; reuse an `upload_id` you already hold, or get an API key — authenticated REST has no such limit |
| `invalid_fields` (gstin) | Malformed GSTIN on enterprise apply | Provide a valid 15-char India GSTIN (e.g. 29ABCDE1234F1Z5) |
| `internal_error` | Our bug | Retry once, then contact support |

Soft validation `warnings` (`no_bleed`, `low_image_dpi`, `odd_page_count`, `large_file_lite_validation`) never block an order.
