Pulp Engine v0.41.0 — Release Notes
This release completes render error classification for the public API routes and sharpens the /render/validate contract, making all three render endpoints operationally honest and machine-readable.
What changed
1. Public render routes: TemplateExpressionError and RenderExecutionError now return 422 with code
POST /render and POST /render/html previously returned an opaque 500 when a template contained an invalid Handlebars expression (TemplateExpressionError) or the PDF engine timed out or crashed (RenderExecutionError). These are now intercepted in-route and returned as classified 422 responses, matching the behavior already in place for the preview routes.
New 422 responses on /render and /render/html:
| Shape | When |
|---|---|
{ "error": "Validation Failed", "issues": [...] } | Data does not satisfy the template’s inputSchema — preserved, no change |
{ "error": "RenderError", "code": "template_expression_error", "message": "..." } | Template has an invalid Handlebars expression |
{ "error": "RenderError", "code": "render_timeout" | "engine_crash", "message": "..." } | PDF engine timed out or crashed (PDF route only) |
The existing { error: 'Validation Failed', issues: [...] } path for RenderValidationError is preserved — callers that already handle this shape are unaffected.
The OpenAPI spec now declares a 422 response on both routes as an anyOf union covering both shapes.
2. /render/validate — sharper contract, retired RENDER_ERROR code
The /render/validate render-check step previously returned all errors under the single RENDER_ERROR code, conflating user-caused template/data problems with unexpected server failures.
Breaking change: RENDER_ERROR is retired. The new codes are:
| issues[].code | Step | Meaning |
|---|---|---|
INVALID_TEMPLATE | 1 — structural | Zod schema validation failure. path indicates the failing field. Unchanged. |
validation_failed | 2 — render check | Data does not satisfy the template’s inputSchema. |
template_expression_error | 2 — render check | Template contains an invalid Handlebars expression. |
Unexpected server failures during the render check now surface as 500 rather than 200 { valid: false, issues: [RENDER_ERROR] }. This correctly separates infrastructure faults from user validation problems — callers no longer need to debug their payload in response to a server error.
3. /render/validate issue codes formally declared in OpenAPI
ValidationResultSchema.issues[].code is now a closed TypeBox union (INVALID_TEMPLATE | validation_failed | template_expression_error) rather than a free string. The generated OpenAPI spec at /docs/json now explicitly enumerates the allowed codes, making the contract machine-readable for API consumers and documentation generators.
Validation
pnpm typecheck— 10/10 passedpnpm lint— 0 errors (1 pre-existing unrelated warning)pnpm --filter @pulp-engine/api test— 582 passed, 41 skipped, 0 failed
Upgrade
/render and /render/html: No breaking changes. The RenderValidationError 422 shape is preserved. TemplateExpressionError and RenderExecutionError change from 500 → 422 with a code — this is strictly an improvement.
/render/validate: The RENDER_ERROR issue code is removed. Callers checking for code === 'RENDER_ERROR' must update to handle validation_failed and template_expression_error. Callers that do not inspect the code field are unaffected. Unexpected server failures now return 500 instead of 200 { valid: false } — callers must handle 500 as a server-side fault (not a validation issue).
No migrations, no credential changes, no new environment variables.
docker pull ghcr.io/OWNER/pulp-engine:v0.41.0