llm-guard

LLM output guard for n8n: LLM-aware JSON extraction + real ajv JSON Schema validation + a repair-loop contract (Valid / Repair / Failed outputs) for HTTP-based LLM workflows. Never throws; every repair attempt is visible in the execution log.

Documentation

n8n-nodes-llm-guard

Validate LLM output against a JSON Schema — and repair it with a visible retry loop. For n8n workflows that call LLMs over plain HTTP Request nodes (Anthropic, OpenAI, local models, anything).

demo

Why this exists (honest prior-art table)

Tool Gap this node fills
Native Structured Output Parser + Auto-Fixing Parser Only work as sub-nodes inside AI Agent / Basic LLM Chain; throw on final failure (workflow error); no $ref support; retries invisible in the execution log
@iamfj/n8n-nodes-schema-validation and similar Great pure validators — but no LLM-awareness (fences, preamble), no repair prompt, no loop contract
Code-node DIY What everyone actually does; this node is that pattern, packaged and tested

LLM Guard is a regular node with three outputs:

                        ┌─► Valid   (parsed, schema-checked data)
your LLM node ─► Guard ─┼─► Repair  (ready-to-inject repair prompt + attempt counter)
        ▲               └─► Failed  (retries exhausted → your DLQ / fallback)
        └────────────────── wire Repair back to your LLM node = the retry loop
  • LLM-aware extraction: strips markdown fences, salvages JSON out of preamble text ("Sure! Here is the result: {...}")
  • Real ajv (draft-07 + formats + $ref), with errors formatted to be actionable by the model — because the error text goes into the repair prompt verbatim: "/intent: value not in allowed set [purchase, support, spam]" repairs itself; "validation failed" doesn't
  • Never throws. Exhausted retries route to the Failed output for your dead-letter handling
  • Every repair attempt is a visible execution step — debugging prompt regressions beats a black-box auto-fixer
  • Broken schema (config error) fails immediately with the compile error — config mistakes never enter the repair loop
  • Zero credentials. Provider-agnostic by construction.

Install

Settings → Community Nodes → n8n-nodes-llm-guard → Install.

Wiring the loop

  1. Your prompt-building node includes the repair feedback when present:
    {{ $json.repairPrompt ? $json.basePrompt + '\n\n' + $json.repairPrompt : $json.basePrompt }}
  2. HTTP Request → your LLM.
  3. LLM Guard: Text = the model's text field (Anthropic: {{ $json.content[0].text }}), Schema = your contract.
  4. Repair output → back to step 1. Valid → continue (parsed data in guarded). Failed → DLQ.

The attempt counter travels on the item (_guard_attempt, configurable) — default budget: initial call + 2 repairs.

Options

Option Default
Max Repair Retries 2 repairs after the first failure
Attempt Field _guard_attempt loop counter field on the item
Parsed Data Field guarded where Valid puts the parsed object
Extraction salvage strict = fences only, no preamble salvage
Repair Instruction — override the repair prompt's final line
Keep Input Data true passthrough of input item fields

Pedigree

Extracted from LeadFlow, a production multi-agent lead pipeline where this exact loop guards two LLM agents, gated by a 50-lead golden-set eval. The core is pure TypeScript with 15 unit tests (npm test).

Development

npm i && npm test        # tsc build + node:test suite

MIT.

Discussion