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 likeResult: [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$triggerand$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:
- Run the workflow once (or Test the upstream node) so it has output.
- Open the upstream node's inspector โ Output panel.
- Right-click the field you want โ Copy as expression. The clipboard now has
{{ $node["Upstream"].json.path.to.field }}. - 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: debugAfter 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.
Related
Found something out of date? This page lives in the Flero docs content set.