USER_ERRORS.md
Rama main · réplica de lectura del repositorio original.
# py-idp API: error codes for end users
Every error the py-idp API returns uses the same envelope:
```json
{
"error": {
"code": "IDP-RATE-001",
"message": "rate limit exceeded",
"type": "RateLimitedError",
"request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"hint": "Too many requests. Slow down and retry after the time indicated by the Retry-After header.",
"docs_url": "https://py-idp.dev/errors#IDP-RATE-001"
}
}
```
| Field | What it means |
|-------|---------------|
| `code` | Stable machine-readable identifier. Switch on this in your client. |
| `message` | Free-form, technical message. Don't parse it -- use `code` instead. |
| `type` | Exception class name. Useful for debugging with Python clients. |
| `request_id` | UUID you can quote when contacting support. |
| `hint` | One-line, user-actionable message. **Show this to end users.** |
| `docs_url` | Anchor link to the matching section below. |
The `hint` and `docs_url` fields are present whenever the code is recognized. If your client can't reach the network for docs, ignore `docs_url` and use the `hint` directly.
## Quick reference
| Code | HTTP | When it fires | What the user should do |
|------|------|---------------|-------------------------|
| `IDP-PARSE-001` | 422 | Document couldn't be parsed (wrong format, corrupt, encrypted) | Use a supported file type (PDF, image, plain text) and ensure it's not password-protected. |
| `IDP-SCHEMA-001` | 422 | Extracted data didn't match the expected schema | Try a clearer document or a different schema. |
| `IDP-BACKEND-001` | 502 | The language model is unreachable | Retry in a few seconds; check the backend status page if it persists. |
| `IDP-OCR-001` | 502 | OCR couldn't read the document | Try a higher-resolution scan or a different document. |
| `IDP-STORE-001` | 500 | Result couldn't be saved | Check server disk space and file permissions, then retry. |
| `IDP-CONF-001` | 503 | Server is misconfigured | Contact the operator. Not a client-side fix. |
| `IDP-RATE-001` | 429 | Rate limit exceeded | Slow down; respect the `Retry-After` header. |
| `IDP-TIME-001` | 504 | Operation took too long | Retry with a smaller document or fewer pages. |
| `IDP-TMPL-404` | 404 | Template not found | Check `/templates` for the list of available templates. |
| `IDP-TMPL-001` | 500 | Template file is malformed | Contact the operator to fix the template. |
| `IDP-UPLOAD-413` | 413 | Upload exceeds server cap | Reduce the file size or raise `IDP_MAX_UPLOAD_BYTES`. |
| `IDP-INT-001` | 500 | Unexpected internal error | Retry shortly; contact support with the `request_id` if it keeps failing. |
| `IDP-CLIENT-400` | 400 | Malformed request | Check the API docs for the expected fields. |
| `IDP-CLIENT-401` | 401 | Missing or invalid authentication | Provide a valid `X-API-Key` header. |
| `IDP-CLIENT-403` | 403 | API key not authorized | Verify the key is correct and has the right permissions. |
| `IDP-CLIENT-404` | 404 | Endpoint or resource doesn't exist | Check the URL. |
| `IDP-CLIENT-405` | 405 | HTTP method not supported | Check the API docs for allowed methods. |
| `IDP-CLIENT-413` | 413 | Request body too large | Reduce the payload size. |
| `IDP-CLIENT-415` | 415 | Unsupported media type | Use a `Content-Type` matching what the endpoint expects. |
| `IDP-CLIENT-422` | 422 | Request body has validation errors | Check `error.details.errors` for the specific field errors. |
| `IDP-CLIENT-429` | 429 | Too many requests | Slow down; respect `Retry-After`. |
| `IDP-SERVER-500` | 500 | Internal server error | Retry shortly; contact support with `request_id`. |
| `IDP-SERVER-502` | 502 | Upstream service unavailable | Retry shortly; check the status page. |
| `IDP-SERVER-503` | 503 | Service starting up or temporarily unavailable | Retry shortly. |
| `IDP-SERVER-504` | 504 | Upstream service timed out | Retry shortly. |
## Detailed entries
### `IDP-PARSE-001` — Document couldn't be parsed
**When it fires:** The parser stage couldn't extract any text from the uploaded document. Common causes:
- File extension isn't supported (only PDF, images, and plain text work)
- File is corrupt or truncated
- File is password-protected
- The PDF uses a format that requires an extra dependency (e.g. Docling) that isn't installed
**What the user should do:** Make sure the file is a supported type and isn't password-protected. If you're uploading a complex PDF, the operator may need to install the Docling extra (`pip install py-idp[docling]`).
**Example response:**
```http
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": {
"code": "IDP-PARSE-001",
"message": "file not found: /uploads/invoice.pdf",
"type": "DocumentParseError",
"request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"hint": "We couldn't read your document. Make sure it's a supported file type (PDF, image, plain text) and isn't password-protected.",
"docs_url": "https://py-idp.dev/errors#IDP-PARSE-001"
}
}
```
### `IDP-SCHEMA-001` — Schema validation failed
**When it fires:** Strict mode is on and the extracted data doesn't match the requested schema. The LLM returned fields with the wrong type, or missing required fields, that strict-mode Pydantic validation caught.
**What the user should do:** Try a clearer document (more typed fields, less handwriting) or use a more permissive schema. Or turn off strict mode if you don't want a hard failure here.
### `IDP-BACKEND-001` — LLM backend unavailable
**When it fires:** The configured language model couldn't be reached. Wraps HTTP 5xx, network timeouts, and auth failures from the upstream provider.
**What the user should do:** Retry in a few seconds. If it persists, check:
- OpenAI status: https://status.openai.com
- Anthropic status: https://status.anthropic.com
- Your own LLM server (if self-hosted)
### `IDP-OCR-001` — OCR failed
**When it fires:** The OCR stage produced no text or failed internally (e.g. Tesseract returned an error, PaddleOCR model load failed, etc.). Distinct from `IDP-PARSE-001`: this means the document *parsed* but OCR *couldn't read it*.
**What the user should do:** Try a higher-resolution scan (300+ DPI recommended) or a different document. If the issue is on the operator side, check that the OCR engine is installed and the model weights are downloaded.
### `IDP-STORE-001` — Storage failure
**When it fires:** Disk full, permission denied on the storage path, or the schema migration failed. Result couldn't be persisted.
**What the user should do:** This is an operator-side issue. Free disk space, fix file permissions, or fix the migration script.
### `IDP-CONF-001` — Server misconfigured
**When it fires:** A required environment variable is missing or invalid (e.g. `DATABASE_URL` set but unparseable). The server fails fast at startup, so this usually means the server isn't running at all.
**What the user should do:** Not a client-side fix. Contact the operator.
### `IDP-RATE-001` — Rate limit exceeded
**When it fires:** The configured per-minute request cap was hit.
**What the user should do:** Slow down. The response carries a `Retry-After: 60` header indicating how long to wait.
**Example response:**
```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
{
"error": {
"code": "IDP-RATE-001",
"message": "rate limit exceeded",
"type": "RateLimitedError",
"request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"hint": "Too many requests. Slow down and retry after the time indicated by the Retry-After header.",
"docs_url": "https://py-idp.dev/errors#IDP-RATE-001"
}
}
```
### `IDP-TIME-001` — Operation timed out
**When it fires:** An internal operation (LLM call, OCR inference, etc.) exceeded its time budget. Default budget is `IDP_LLM_TIMEOUT` seconds (60s by default).
**What the user should do:** Retry with a smaller document or fewer pages. If your documents are intrinsically large, ask the operator to raise the timeout.
### `IDP-TMPL-404` — Template not found
**When it fires:** You asked for a template that isn't registered (e.g. `/templates/invoice-old` when only `invoice` exists).
**What the user should do:** List available templates with `GET /templates` and use one of those.
**Example response:**
```http
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"code": "IDP-TMPL-404",
"message": "template 'invoice-old' not found in registry",
"type": "TemplateNotFoundError",
"request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"hint": "That template doesn't exist. Check the /templates endpoint for the list of available templates.",
"docs_url": "https://py-idp.dev/errors#IDP-TMPL-404"
}
}
```
### `IDP-TMPL-001` — Template file malformed
**When it fires:** A template `.md` file has bad YAML frontmatter, a missing required field, or an invalid schema reference.
**What the user should do:** Operator-side fix. Check the template file in the configured `IDP_TEMPLATE_DIR`.
### `IDP-UPLOAD-413` — Upload too large
**When it fires:** The uploaded file exceeded the configured `IDP_MAX_UPLOAD_BYTES` (25 MB by default).
**What the user should do:** Reduce the file size (compress images, drop unnecessary pages), or ask the operator to raise the server's cap.
**Example response:**
```http
HTTP/1.1 413 Payload Too Large
Content-Type: application/json
{
"error": {
"code": "IDP-UPLOAD-413",
"message": "payload too large: 31457280 bytes > max 26214400",
"type": "FileTooLargeError",
"request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"hint": "Your upload is too large. Reduce the file size or raise the server's max_upload_bytes setting.",
"docs_url": "https://py-idp.dev/errors#IDP-UPLOAD-413"
}
}
```
### `IDP-INT-001` — Unexpected error
**When it fires:** An unhandled exception bubbled up. Should be rare -- this is the catch-all for things we didn't classify.
**What the user should do:** Retry in a few seconds. If it persists, contact the operator with the `request_id`.
### `IDP-CLIENT-4xx` and `IDP-SERVER-5xx` — HTTP-derived codes
Codes prefixed `IDP-CLIENT-` and `IDP-SERVER-` are generated automatically from HTTP status codes (see `idp.errors.classify_status`). They cover:
- 400, 401, 403, 404, 405, 413, 415, 422, 429 (client-side)
- 500, 502, 503, 504 (server-side)
The `hint` field for each tells the user what to do. See the [Quick reference](#quick-reference) table for the full list.
## Versioning
`code`, `hint`, and `docs_url` are stable. New codes may be added; existing codes may receive a refined hint message but the meaning won't change without a major version bump. Client code should:
- Branch on `code`, not `message` or `type`
- Treat unknown codes as `IDP-INT-001` (show the generic "something went wrong" message)
- Always surface `request_id` in support tickets