Skip to main content
The guardrails node validates a value already in run state and records the outcome. It runs up to four checks over a single source value — JSON Schema validation, regex validation, PII detection, and a hallucination check — then takes one of four actions: block, warn, transform (mask PII), or route. Unlike most node types, it produces no new business data of its own; its job is to inspect existing data and write a structured verdict that a later node can act on. A guardrails node does not call a language model or any managed service, so it consumes no credits and never hits the billing gate. It is a pure, in-process validation step. For the engine that compiles and runs nodes (the state graph, run state, and edges), see Workflow engine & nodes. For the {{node_id.field}} reference syntax used throughout this page, see Variables & references.

What the node does

When a run reaches a guardrails node, the engine:
  1. Resolves the single source reference (for example {{node_extract.json}}) against run state to get the value to inspect.
  2. Runs each enabled check in turn — JSON validation, regex validation, PII detection, hallucination check — recording a per-check result.
  3. Decides whether the node passed. By default, the node passes only if every enabled check passed. With continue_on_partial_failure set, the node passes if at least one enabled check passed.
  4. Applies the configured on_failure action and writes a single result object into state under the node’s own id.
The node writes its verdict to state but does not itself stop the run or change the graph path. Routing is a separate step you wire downstream — see Pass/fail routing. This split is the most important thing to understand about this node, so it is called out again below. The guardrails node is retry-wrapped like most node types: if the node function raises, it retries per the node’s retry_config (default 3 attempts) and emits the standard node_started, node_retry, and node_error events on the run stream — see SSE run streaming. A failed validation is not an exception, though: a check that returns valid: false is a normal result, not a retryable error, so a blocked or routed verdict never triggers a retry.
The on_failure: block action does not halt the run. It records blocked: true and an error string in the node’s result; the graph continues to the next edge as written. To actually stop or divert a run on a failed guardrail, read the node’s result with a downstream conditional node. See Pass/fail routing.

GuardrailsNodeConfig reference

Every guardrails node carries a guardrails_config object. A node with no guardrails_config raises a build-time ValueError. Each of the four checks is optional and independently toggled with its own enabled flag — a check object that is present but enabled: false is skipped, and so is a check that is absent.
string
required
The value to validate, written as a single {{node_id.field}} reference — for example {{node_extract.json}} or {{input.payload}}. Resolved against run state to its native typed value before any check runs. If it resolves to null (missing reference), the node returns valid: false with an error and no checks run. Non-string values are coerced to a string for the text-based checks (regex), while JSON validation and PII detection operate on the native value, including nested objects and arrays.
JsonValidationConfig
JSON Schema (Draft 7) validation of the resolved source value. Optional. See JSON Schema validation.
RegexValidationConfig
Regular-expression validation of the source value as text. Optional. See Regex validation.
PIIDetectionConfig
Detection of personally identifiable information, with block, mask, or flag handling. Optional. See PII detection.
HallucinationCheckConfig
A grounding/hallucination check. Optional. Currently a placeholder — see Hallucination check.
string
default:"block"
The action when the node does not pass. One of block, warn, transform, route. Defaults to block. This action only annotates the node’s result object — it does not change the graph path on its own. See The on_failure action.
string
The target node id to record when on_failure is route. Written into the result as route_to; a downstream conditional reads it to actually branch. Has no effect for other on_failure values.
boolean
default:"false"
When false (default), the node passes only if all enabled checks pass. When true, the node passes if at least one enabled check passes. Use it when several checks are advisory and you only want to fail when everything fails.

JSON Schema validation

JsonValidationConfig validates the resolved source value against a JSON Schema using a Draft 7 validator.
boolean
default:"false"
Turn the check on. When false, JSON validation is skipped entirely.
object
The JSON Schema to validate against. Also accepted under the field name schema_def. When no schema is provided the check passes with a “no schema provided” message rather than failing.
boolean
default:"false"
When true, the validator adds additionalProperties: false to the top-level schema before validating, so any property not declared in the schema is a failure.
On a schema violation the check result is valid: false with an errors array (capped at the first 5), each entry carrying message, path, and schema_path. An invalid schema or other internal error returns valid: false with a single error string.

Regex validation

RegexValidationConfig matches the source value, rendered as text, against a regular expression.
boolean
default:"false"
Turn the check on.
string
The regular expression to apply. If empty, the check passes with a “no pattern provided” message.
string
Optional regex flags as a string of letters: i (ignore case), m (multiline), s (dotall). Any combination, for example im.
string
default:"contains"
How the pattern is applied: full_match (the pattern must match the entire string), contains (the pattern is found anywhere), or search (first match anywhere). contains and search behave identically. Defaults to contains.
boolean
default:"false"
Invert the result. With negate: false (default), the check passes when the pattern is found and fails when it is not. With negate: true, the check passes when the pattern is not found and fails when it is — the standard way to enforce a “must NOT contain” content-safety rule.
string
A custom message to use on failure instead of the generated default.
On a passing match the result includes the matched substring and its start/end offsets. On failure it carries valid: false and the error (your error_message if set). An invalid pattern returns valid: false with an “Invalid regex pattern” error.

PII detection

PIIDetectionConfig scans the source value — including nested objects and arrays — for personally identifiable information and handles any findings.
boolean
default:"false"
Turn the check on.
string[]
default:"['email', 'phone', 'credit_card']"
The PII categories to scan for. Defaults to email, phone, and credit_card. Supported values: email, phone, credit_card, ssn, ip_address, mac_address, iban, url, date_of_birth, passport, drivers_license, tax_id, and custom. Each maps to a built-in regular expression; custom is matched against custom_patterns instead.
string
default:"mask"
What to do when PII is found: block (the check fails, so the node does not pass), mask (replace matches in transformed_data, the check still passes), or flag (record findings as a warning and continue, the check still passes). Defaults to mask.
object
A map of pattern_name to regex string, applied only when custom is in pii_types. Findings are typed as custom:<pattern_name>. An invalid custom pattern is logged and skipped rather than failing the check.
string
default:"en"
Locale for locale-specific patterns. Defaults to en. Setting tr swaps in Turkish phone and TCKN (national-ID / tax-id) patterns. Other values fall back to the default patterns.
string
default:"*"
The character used when masking. Defaults to *.
boolean
default:"true"
When true (default), a masked value is replaced character-for-character so its length is unchanged. When false and the value is longer than 4 characters, the first and last characters are kept and the middle is masked (for example j*****e); shorter values are fully masked.
Each finding records its type, the matched value, the start/end offsets, and — for matches inside nested data — a path (for example customer.email or items[0]). Masking with action: mask writes the cleaned value to transformed_data and leaves the check passing; the masked output is what you reference downstream.
The built-in PII patterns are pragmatic regular expressions, not a certified PII engine. They can miss values (false negatives) and match non-PII (false positives) — for example the generic tax_id pattern matches any 10–11 digit run. Treat PII masking as defense-in-depth, not a guarantee, and validate against your own data before relying on it for compliance.

Hallucination check (placeholder)

HallucinationCheckConfig is not yet implemented. When enabled, the node records a result of valid: true, checked: false, and the message Hallucination check requires knowledge base configuration (coming soon) — it never fails the node and never inspects content. The config fields below are accepted and stored for forward compatibility but have no runtime effect today.
boolean
default:"false"
Turn the check on. Because the check is a placeholder, enabling it adds the stub result above but does not validate anything.
string
Intended knowledge base for grounding (future). If unset while the check is enabled, a warning is logged.
string
Intended detection model (future). No effect today.
number
default:"0.7"
Intended confidence floor, 0.01.0 (future). No effect today.
string
default:"self_check"
Intended detection method: self_check, knowledge_base, or hybrid (future). No effect today.
Do not rely on the hallucination check to catch anything yet. For grounding answers against your documents today, retrieve with a Knowledge node and validate the result with the JSON or regex checks here.

The on_failure action

When the node does not pass, on_failure decides what extra fields are written to the result object. None of these actions changes the graph path by themselves — they annotate the verdict so a later node can act on it.

Inputs and outputs

Input. A guardrails node reads exactly one value from run state — the resolved source reference. It does not take an input_mapping. Output. Like every node, it writes its result to state under its own id, so a later step references it as {{<guardrails_node_id>.field>}}. The result object has this shape:
boolean
The overall verdict. true if the node passed (all enabled checks passed, or — with continue_on_partial_failure — at least one did); otherwise false.
string
The source reference that was validated, echoed back.
object
Per-check results keyed by json_validation, regex_validation, pii_detection, and hallucination_check. A check that did not run is null; a check that ran holds its own result object (each with its own valid plus check-specific fields described above).
any
The source value exactly as resolved, before any masking.
any
The value after PII masking, when masking changed it; otherwise null. Reference this (not original_data) downstream when you want the cleaned value.
array
The list of PII findings (each with type, value, start, end, and optional path), or null when none were found.
boolean
Present and true only when the node failed and on_failure is block. Accompanied by error.
string
Present only when the node failed and on_failure is warn.
string
Present only when the node failed and on_failure is route — equals failure_route.
boolean
Present and true only when the node failed and on_failure is transform.
string
Present when the node was blocked, or when the source reference could not be resolved (Source data not found: <source>).

Pass/fail routing

The guardrails node decides pass or fail, but it never creates a branch in the graph on its own. To act on the verdict you read the node’s result with a downstream conditional node, exactly as you would read any other node’s output. This is the one workflow that turns a guardrail into a real gate. A common pattern:
  1. The guardrails node node_check validates {{node_extract.json}} with on_failure: route and failure_route: "node_reject".
  2. A conditional node after it branches on {{node_check.valid}} — route false to your rejection path and true to your happy path.
Because route_to and blocked are plain data fields, you can branch on whichever you prefer:
Conditional that gates on the guardrail
Setting on_failure: route and failure_route alone does not divert the run — the engine has no built-in edge that reads a guardrails node’s route_to. Only a conditional node converts the verdict into a branch. Treat failure_route as a hint you then honor with a conditional that routes to the same target.

Credit impact

The guardrails node performs only local validation — no LLM call, no managed retrieval, no external request — so it consumes no credits and is never subject to the usage gate. It is safe to use liberally for input checking and output validation without affecting your credit balance. (The hallucination check would change this once implemented, since grounding would call a model; today it is a no-op.)

Errors

A failed validation is data, not an exception — it never raises and never retries. The node only retries on a genuine runtime exception. The validation routes (workflow save/update) return validation problems as the {detail} HTTPException shape; see Errors & status codes. The guardrails node itself never emits a DenialEnvelope, because it makes no metered call.

Worked example

Validate an upstream extraction against a schema, mask any leaked PII, and route to a rejection path if the data is invalid. An LLM node node_extract produces a JSON object under {{node_extract.json}}; the guardrails node node_check validates it and masks emails and phone numbers; a conditional node node_gate branches on the verdict.
For that input the extraction is schema-valid, so JSON validation passes, and PII detection finds the email and phone and masks them. The guardrails node’s state entry looks like this:
Because valid is true, node_gate falls through to node_continue, which reads the cleaned record from {{node_check.transformed_data}}. If the extraction had been missing email, JSON validation would fail, valid would be false, route_to would be node_reject, and node_gate would branch there. To stream and observe the verdict live, see SSE run streaming; to run a workflow end to end, see Run a workflow.

Conditional node

Read a guardrail’s verdict and branch the run on it — the routing half of pass/fail gating.

Node types reference

All nine node types and the state convention they share.

Function node

The built-in schema-validation function, an alternative when you want validation outside a guardrail.

Variables & references

The {{node_id.field}} reference system the source field uses.