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
| Message | Cause & fix |
|---|---|
Template is not published | The template is a draft (or archived). Publish it in the dashboard or via POST /v1/templates/:id/publish. |
No table sections found | You 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
| Message | Cause & fix |
|---|---|
Missing x-api-key header | No key sent. The SDK sends it for you — check the key you constructed the client with isn’t empty. |
Invalid API key | Key mistyped, or invalidated by a key rotation. |
Public key requires Origin header | Public key used outside a browser context (e.g. server-side). Use the secret key on servers. |
Invalid Origin header | The Origin/Referer value isn’t a valid URL. |
Domain <hostname> is not in allowedDomains | Add 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 headers | Browser client constructed without userId/userHash. |
Invalid x-user-hash | Hash doesn’t verify: signed with the wrong signing secret, for a different user ID, or keys were rotated. Recompute with signUserId. |
403 Forbidden
| Message | Cause & fix |
|---|---|
Secret key required to rotate credentials | POST /v1/auth/rotate-keys called with a public key. Rotation is a server-side, secret-key operation. |
404 Not Found
| Message | Cause & fix |
|---|---|
Template not found | Wrong template ID, another org’s template, or (for public keys) another user’s template. |
Document not found | Wrong document ID, another org/user’s document, or the render never completed. |
Asset not found | Wrong 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.