Skip to main content

Exit codes

Every command ends with one of six exit codes. A script or CI step can branch on them without reading the output.

CodeMeaningTypical cause
0SuccessAlso --help and --version
1Validation or test failureA template has errors or does not match its snapshot, a generated file is out of date, a preview could not be rendered; see the list below. Diagnostics are printed.
2Usage errorUnknown command or flag, a missing argument, init in a folder that already has formfeed.json, no formfeed.json for a command that needs a project, a template or data set that does not exist, a formfeed.json or user config that is not valid JSON, a port of formfeed dev that is in use, and API answers in the 4xx range not listed under 3 and 5, such as 404 template_not_found, 409 conflict (templates push after someone saved a newer version, partials push) or a 422 template error
3Authentication errorNo key, an unknown or revoked key (401), and every 403: a missing scope, a plan that does not include the feature, test_output_unavailable. A browser login that was refused or whose code expired.
4Network or server errorTimeout, connection failure, 5xx (503 after the retries), a render or conversion that failed while the CLI waited for it (render, pdf convert), timeout when it did not finish in time, a library file files pull could not download, and any error the CLI does not classify
5Quota or rate limit402 quota_exceeded, 429 rate_limited after the retries

The CLI calls the API through the TypeScript SDK, so 429 and 503 are retried up to three times after the server's Retry-After before a code is chosen. An API answer maps to a code by its status: 401 and 403 give 3, 402 and 429 give 5, any other 4xx gives 2, and everything else 4.

Exit code 1 comes from:

  • validate finding an error, including a missing partial. A variable that is missing from the data set is a warning and does not fail.
  • test finding a snapshot difference, a data set with errors, or a Word or PowerPoint template that cannot be filled. A data set without an approved snapshot does not fail.
  • types --check when the file differs from what formfeed types would write.
  • ci preview when at least one render failed or a Word or PowerPoint template could not be filled; the summary lists it.
  • renders pull --run or --snapshot when the template does not render with the pulled data.
  • render when a Word or PowerPoint template cannot be filled (the findings name the part and paragraph), and when a template whose pdf.ua check is strict fails the PDF/UA-1 validation; the CLI prints the rules that failed.
  • einvoice when the template's e-invoice settings are invalid or the _invoice block of the data set does not make an e-invoice.
  • templates push when a template includes a partial that has no file, and templates push, channels set, promote and rollback when the schema check finds a breaking change and --allow-breaking is missing.
  • A template folder that holds template.html and template.docx (or template.pptx) at once, a template.json whose kind does not match the folder's file, a JSON file in the folder that does not parse, and a .formfeed/brand.json that does not parse.
  • import apitemplate when not a single template could be imported.

Two cases that look alike end differently. A render the API refuses in its answer (a problem such as 422 template_runtime_error or 422 page_limit_exceeded) exits with 2 in render and stops ci preview with 2 before its summary is written; a render that fails after it was queued exits with 4 in render and is listed as failed by ci preview, which then exits with 1.

Output on failure​

Without --json, a failure prints error: <message> to stderr, followed by the problem's field errors when the API sent any.

With --json, a failure prints a single JSON object to stdout with ok: false, error (the message), exit_code and details, which holds the problem from the server for API errors. For formfeed render invoice --remote --json when the workspace has no published template invoice:

{
"ok": false,
"error": "No published template \"invoice\" in workspace production",
"exit_code": 2,
"details": {
"type": "https://docs.formfeed.dev/errors/template-not-found",
"title": "Template not found",
"status": 404,
"detail": "No published template \"invoice\" in workspace production",
"code": "template_not_found",
"request_id": "req_…"
}
}

Commands that print their own result first (validate, test, ci preview, renders pull, import apitemplate) exit with the code without a second object; their result carries ok: false or the failed rows. An unknown command or flag prints the usage message to stderr, never a JSON object.

formfeed render invoice --json || echo "failed with $?"