Skip to content
Docs
flero.ai

Debugging expressions

When an expression doesn't resolve, Flero leaves a marker in the output instead of silently failing. Read the marker, fix the expression, re-run.

๐Ÿ“ธ Screenshot needed: expressions__expr-error.png, a node's output panel showing a string like Result: [EXPR-ERROR: Node "HTPR Request" not found. Available: [HTTP Request, Log]].


The [EXPR-ERROR: โ€ฆ] marker

Every failed expression block is replaced with a marker of the form:

[EXPR-ERROR: <reason>]

The marker uses square brackets, not braces, so downstream evaluators don't re-parse it and silently strip it.

Common reasons:

Marker What it means Fix
Node "X" not found. Available: [A, B, C] Typo or wrong name Copy the exact display name from the canvas
unknown reference "x.output.y" โ€” expected $node["Name"]โ€ฆ You used the shorthand instead of $node["โ€ฆ"] Wrap in $node["x"]
<reason> (anything else) Runtime error during evaluation Read the reason; usually missing field

The marker tells you the available node names for typos. That's deliberate, you can self-correct from the output.


Strategy 1, Click the Data Mapper

The fastest way to write a correct expression is not to type it: click the ๐Ÿ”— chain icon next to a field. The Data Mapper popover shows a tree of every upstream node's output. Click a leaf, Flero inserts the right $node["โ€ฆ"].json.<path> for you.

The popover also previews the resolved value before you save. If the preview shows what you expected, the expression is correct.

๐Ÿ“ธ Screenshot needed: expressions__data-tree.png, Data Mapper popover open over a field, showing a tree of $trigger and $node["HTTP Request"] outputs with one leaf hovered, and a live preview of the resolved value below.


Strategy 2, Run, inspect, iterate

When in doubt:

  1. Run the workflow once (or Test the upstream node) so it has output.
  2. Open the upstream node's inspector โ†’ Output panel.
  3. Right-click the field you want โ†’ Copy as expression. The clipboard now has {{ $node["Upstream"].json.path.to.field }}.
  4. Paste into the field where you need it.

This is exact, no typos possible.


Strategy 3, Read the [EXPR-ERROR] literally

The marker is designed to be informative. Read every word of the reason text:

  • "Node not found" โ†’ typo or out-of-scope reference.
  • "Field not found" โ†’ the path navigates into something that didn't exist.
  • "unknown reference" โ†’ you forgot the $node["โ€ฆ"] wrapper.
  • Anything else โ†’ a runtime exception. Often a type mismatch (calling .toLowerCase() on a number).

Strategy 4, Reduce the expression

For long compound expressions, debug piece-by-piece. Replace the full expression temporarily with just {{ $node["X"].json }} (the whole output) and look at the inspector, is the node returning what you expected? Then add .path.to.field one segment at a time, running each step.


Common pitfalls

Forgetting $node["โ€ฆ"]

// Wrong โ€” looks like a Flero expression but isn't
{{ start.output.x }}

// Right
{{ $node["start"].output.x }}

The evaluator catches this specifically: you'll see [EXPR-ERROR: unknown reference "start.output.x" โ€” expected $node["Name"], $trigger, $workflow, $input, or $env. Did you mean $node["โ€ฆ"].output.field ?].

Case sensitivity

// If the node is named "HTTP Request"
{{ $node["HTTP request"].json.body }}        // โŒ "Node not found"
{{ $node["HTTP Request"].json.body }}        // โœ…

Hyphenated names

// Node named "my-fetch"
{{ my-fetch.output.x }}                      // โŒ won't parse
{{ $node["my-fetch"].output.x }}             // โœ…

The shorthand-detector only catches names made of \w characters. Hyphenated names must use the $node["โ€ฆ"] form.

Referencing a node that didn't run

If the upstream node is on an If's true branch and the If went false, it has no output. Expressions referencing it fail.

Use an If / Switch in the consuming branch to guard, or move the reference upstream of the branching point.

null substituted as the string "null"

"Hello, {{ $trigger.body.name }}"    // if name is null โ†’ "Hello, null"

Use the default-value pattern (Code node or Data Transform) to substitute a fallback.

0 is a valid value, not "missing"

isEmpty on the number 0 is false. If you want "missing or zero", check both: isEmpty OR equal 0.

Confusing $trigger.body and $trigger

$trigger.body is the request body of a webhook trigger. $trigger is the whole trigger payload (body + headers + query + โ€ฆ). Most of the time you want $trigger.body.<field>.


Logging for debug

Drop a Log node mid-workflow with the entire upstream output to see exactly what you're working with:

Message:    DEBUG upstream output: {{ $node["HTTP Request"].json }}
Level:      debug

After the run, open the execution detail and read the resolved message. This is the cheapest way to confirm "what is actually here".


Tips & gotchas

  • [EXPR-ERROR] propagates, if a downstream node receives an expression with the marker baked into a string field, the marker stays as literal text in the output. Treat it as a build-time error, not a runtime warning.
  • The Data Mapper is the cure for 90% of typos. Train yourself to reach for it.
  • When in doubt, log first. Dropping a Log node is faster than guessing.


Found something out of date? This page lives in the Flero docs content set.