Skip to content

Errors

Every failure raised by the SDK is an instance of PoliPageError or one of its subclasses. The code attribute tells you what went wrong; the request_id attribute is what to quote when filing a support ticket.

PoliPageError is the base catch-all. Two transport-level branches (APIConnectionError and its APITimeoutError subclass) and one HTTP-status branch (APIStatusError, with per-status subclasses like RateLimitError, NotFoundError, BadRequestError) cover every failure mode.

from poli_page import PoliPage, PoliPageError
client = PoliPage()
try:
client.render.pdf({"project": "billing", "template": "invoice", "data": {}})
except PoliPageError as err:
print(err.code, err.request_id, err.message)

These originate inside the SDK before any HTTP call (or in response to a network-layer failure). They are lowercase.

Code When Recovery
invalid_options The arguments passed to the PoliPage constructor are invalid (missing api_key, malformed base_url, etc.). The message is `apiKey is required`. Fix the constructor call. Raised synchronously.
network_error TCP/TLS-layer failure reaching the API. The message is `Network request failed`; the httpx exception is the `__cause__`. Automatically retried up to max_retries times.
timeout The request did not complete within the configured `timeout`. The message is `Request timed out after <ms>ms`. Automatically retried up to max_retries times. Raise `timeout` if it keeps tripping.
DOWNLOAD_FAILED The S3 second-hop download (after `render.pdf` / `render.pdf_stream`) failed: `Failed to download PDF: HTTP <status>` with the storage `status` (an expired URL gets 403), `Failed to download PDF: timeout` without one when it outlasts `timeout`, or `Failed to download PDF: network error` without one, also when the connection drops while the body is read. Never retryable, whatever the storage status (`is_retryable()` is `False`). Re-fetch the descriptor via documents.get(id) — presigned URLs expire after 15 minutes.
invalid_response A 2xx answer whose body is not JSON, from a method that expects JSON (the render call, `documents.get`, `documents.thumbnails`), usually from a proxy or a captive portal. Raised as `InvalidResponseError` with the real 2xx as `status` and the message `Invalid response: HTTP <status> body is not JSON`; `to_payload()` answers 502. Not retried. Check the network path to the API (proxy, `base_url`).
io_error `render_to_file` / `async_render_to_file` could not write the file (a parent directory, the temporary file, a write or the final rename), or the target exists but is not a writable regular file (`Failed to write PDF: <target>: not a regular file` for a directory or a FIFO). No `status`; the message is `Failed to write PDF: <target>: <reason>`, with the path as you gave it, and the `OSError`, when there is one, is the `__cause__`. The target is left as it was. Not retried. Fix the path, permissions or free space.

Returned by the Poli Page API. Uppercase, snake-case. The SDK forwards the code verbatim.

Code When Recovery
INVALID_API_KEY The API key is malformed or revoked. Create a new key in the dashboard.
MISSING_API_KEY No API key was provided in the request. Check the constructor was called with `api_key`.
PROJECT_NOT_FOUND No project with this slug exists in the organization. Check the `project` slug.
PROJECT_NOT_IN_ENVIRONMENT The project was never published to the key's environment, or was removed from it. Publish the project to the environment of the key you render with.
TEMPLATE_NOT_FOUND The template is not in the project's copy published in the key's environment. Check the `template` slug; publish the project again if the template is new.
DOCUMENT_GONE The document was deleted, or is a `sandbox` document older than 30 days. Render it again.
VALIDATION_ERROR The request body failed validation (for example thumbnail options out of bounds). Inspect `err.message` for the failing field.
MISSING_DATA The request body lacks a required `data` field. Pass `data` (`{}` when the template needs none) on every render call.
QUOTA_EXCEEDED The organization reached its monthly quota (429). Not retried: it lasts until the monthly reset. Upgrade the tier for more renders.
OVERAGE_CAP_EXCEEDED The organization reached its overage cap (429, paid tiers). Not retried: it lasts until the monthly reset. Raise the cap in the dashboard.
STORAGE_ACCESS_DENIED The organization's own storage bucket refuses access (502). Not retried: restore the bucket role, then call again.
RATE_LIMIT_EXCEEDED Too many render requests for this key in a short window. Automatically retried; spread the load.
PUBLISH_IN_PROGRESS The project is being published into this environment (503 with `Retry-After`). Automatically retried up to `max_retries` times (default `2`, three attempts in all), each retry waiting `Retry-After` capped at 30 seconds. A publish that outlasts the retries surfaces this error: catch it and retry later.
ORGANIZATION_PAYMENT_GRACE The organization has unpaid invoices: it is read-only and renders are refused. Update the payment method in the dashboard.
INTERNAL_ERROR The API returned 5xx. Also the code of an error answer whose body is not JSON (a gateway page), with its real status and the message `HTTP <status>`. Automatically retried; contact support if it persists.

The full list of API codes lives in the reference.

from poli_page import PoliPage, PoliPageError, RateLimitError
client = PoliPage()
try:
pdf = client.render.pdf({
"project": "billing",
"template": "invoice",
"data": {"invoiceNumber": "INV-001", "total": 1280},
})
except RateLimitError:
# RATE_LIMIT_EXCEEDED outlasted the retries, or QUOTA_EXCEEDED / OVERAGE_CAP_EXCEEDED,
# which the SDK never retries: queue the job for later.
pdf = None
except PoliPageError as err:
print(f"render failed: {err.code} ({err.request_id})")
raise