Skip to content

render_failed

HTTP 500. The request was valid, the data passed the schema, and the render itself did not finish. A failed render is never billed.

500 — a template mistake
{
"error": {
"type": "render_failed",
"message": "Template failed to render: undefined filter: currncy",
"docs_url": "https://galleyrender.com/docs/errors/render_failed",
"details": { "stage": "template" }
}
}
500 — the browser gave up
{
"error": {
"type": "render_failed",
"message": "Chromium render failed: page.setContent: Timeout 20000ms exceeded.",
"docs_url": "https://galleyrender.com/docs/errors/render_failed",
"details": { "engine": "chromium", "format": "pdf" }
}
}

Four raise sites:

  • Liquid. The template threw while rendering — an undefined filter, a bad argument, a broken expression. details.stage is "template".
  • Chromium. The page failed to load or capture within 20 seconds (CHROMIUM_PAGE_TIMEOUT_MS), usually because it waits on something it will never get. details.engine is "chromium".
  • Satori. The markup is outside the supported flexbox subset. details.hint says so: every element needs an explicit display, inline styles only.
  • Abandoned. A queued render that a worker failed to complete three times is marked failed with “Render abandoned after 3 attempts.” This is stored on the render, not returned to a call.

On a synchronous render the whole serialized render is included at details.render, so you still have the id. On a queued render nothing is returned at all — the failure is on the render row, readable with GET /v1/renders/:id or delivered as a render.failed webhook.

Read the message: it names the filter, the timeout or the unsupported construct. Bisect with a smaller payload to find which branch of the template is at fault. Only money and date_medium exist beyond standard Liquid. For a Chromium timeout, remove whatever the page waits on — a slow webfont, an unreachable script, an animation that never settles.

Rarely. A template mistake is deterministic. A timeout occasionally is not — one retry is reasonable, a loop is not.