Skip to Content

Errors

Non-2xx responses have a JSON body whose message field is listed below verbatim. Both SDK clients (Reforgio, ReforgioServer) throw a ReforgioError carrying that message and the HTTP status:

class ReforgioError extends Error { readonly statusCode: number // HTTP status of the failed response // .message is the server's exact message from the tables below }

Handling recipe

import { ReforgioError } from '@reforgio/sdk-core' // (also exported from '@reforgio/sdk-core/server' and re-thrown by all @reforgio/sdk-react hooks) try { const doc = await client.render(templateId, data) window.open(doc.downloadUrl) } catch (err) { if (!(err instanceof ReforgioError)) throw err // network failures, bugs — let them surface switch (err.statusCode) { case 400: // bad input for this template — show err.message, it's specific break case 401: // credentials problem — see the 401 table for the exact cause break case 404: // wrong ID or another organization's resource break case 429: // rate limited (100 req/min per key) — back off and retry break default: // 5xx — retry with backoff or surface a generic failure break } }

400 Bad Request

MessageCause & fix
Template is not publishedThe template is a draft (or archived). Publish it in the dashboard or via POST /v1/templates/:id/publish.
No table sections foundYou rendered format: 'xlsx' on a template with no table section. Add one, or render PDF.
Section N: "{{…}}" is not a valid expression …On template create/update: a section contains a {{…}} with spaces or an unknown helper (e.g. literal text like {{Tak / Nie}}). Variables must be single names like {{invoice_number}}; escape literal braces as \{{…}}. The message names the section and the exact expression.
Template contains an invalid {{…}} expression (…)On render: the template (saved before expression validation existed) holds a broken {{…}}. Fix the expression in the template editor.
(validation messages)Malformed body — e.g. missing templateId, data not an object, format not pdf/xlsx, or (on template create) missing formats/sections. The message lists the offending fields.

401 Unauthorized

MessageCause & fix
Missing x-api-key headerNo key sent. The SDK sends it for you — check the key you constructed the client with isn’t empty.
Invalid API keyKey mistyped, or invalidated by a key rotation.
Public key requires Origin headerPublic key used outside a browser context (e.g. server-side). Use the secret key on servers.
Invalid Origin headerThe Origin/Referer value isn’t a valid URL.
Domain <hostname> is not in allowedDomainsAdd the hostname under Settings → Allowed domains (exact hostname or a parent domain — subdomains of allowed entries pass).
Public key requires x-user-id and x-user-hash headersBrowser client constructed without userId/userHash.
Invalid x-user-hashHash doesn’t verify: signed with the wrong signing secret, for a different user ID, or keys were rotated. Recompute with signUserId.

403 Forbidden

MessageCause & fix
Secret key required to rotate credentialsPOST /v1/auth/rotate-keys called with a public key. Rotation is a server-side, secret-key operation.

404 Not Found

MessageCause & fix
Template not foundWrong template ID, another org’s template, or (for public keys) another user’s template.
Document not foundWrong document ID, another org/user’s document, or the render never completed.
Asset not foundWrong asset ID or another org’s asset.

429 Too Many Requests

The per-key rate limit is 100 requests per minute. Space out bulk renders; on 429, wait and retry with exponential backoff.