n8n Expression Error Diagnosis
Diagnose and fix expression evaluation failures in n8n v1.x workflows.
For error type details see references/methods.md.
For before/after fixes see references/examples.md.
For anti-patterns see references/anti-patterns.md.
Quick Diagnostic Table
| Symptom |
Cause |
Fix |
undefined when accessing $json.field |
Field does not exist on current item |
Check field name spelling; use $json?.field or $ifEmpty($json.field, fallback) |
TypeError: Cannot read properties of undefined |
Accessing nested field on null/undefined parent |
Chain optional access: $json.parent?.child?.value |
$itemIndex is not defined in Code node |
$itemIndex is NOT available in Code node |
Use items.indexOf(item) or loop index variable instead |
$secrets is not defined in Code node |
$secrets is NOT available in Code node |
Use $env.SECRET_NAME or pass secret via preceding Set node |
$response is not defined |
$response used outside HTTP Request node |
ONLY use $response in HTTP Request node parameter fields |
Paired item not found |
Item linking broken between nodes |
Use $("<Node>").first() or $("<Node>").all()[index] instead of .item |
| JMESPath returns unexpected result |
Parameter order swapped |
ALWAYS use $jmespath(object, searchString) — object first, search second |
| Expression returns empty string |
Field exists but value is null, "", or undefined |
Use $ifEmpty($json.field, "default") to provide fallback |
$getWorkflowStaticData returns empty |
Static data not available during manual test |
ALWAYS test static data with active workflow (webhook/trigger), NEVER manual execution |
TypeError: X is not a function |
Calling n8n extension method on wrong type |
Verify data type: .extractEmail() requires string, .average() requires array |
$("<Node>").item returns wrong data |
Expression evaluated in non-matching context |
Use $("<Node>").itemMatching(index) in Code node; use .first() or .all() for explicit access |
Python AttributeError on item access |
Using dot notation in Python Code node |
ALWAYS use bracket notation: item["json"]["field"] |
$pageCount is not defined |
Used outside HTTP Request node pagination |
$pageCount is ONLY available in HTTP Request node |
| Number treated as string in comparison |
n8n expression returned string type |
Explicitly convert: Number($json.price) or use parseInt()/parseFloat() |
| Date comparison fails |
Comparing string dates instead of DateTime |
Convert with .toDateTime() then compare with .diffTo() or .isBetween() |
Variable Availability Matrix
Use this matrix to determine which variables are available in each context.
| Variable |
Expression Fields |
Code Node (JS) |
Code Node (Python) |
HTTP Request Node |
$json / $binary |
YES |
YES |
_json / _binary |
YES |
$input.item |
YES |
YES (each-item mode) |
_item |
YES |
$input.all() |
YES |
YES |
_items |
YES |
$("<Node>").item |
YES |
NO (use .itemMatching()) |
NO |
YES |
$("<Node>").itemMatching() |
YES |
YES |
YES (_("<Node>")) |
YES |
$itemIndex |
YES |
NO |
NO |
YES |
$runIndex |
YES |
YES |
YES |
YES |
$secrets |
YES |
NO |
NO |
YES |
$env |
YES |
YES |
_env |
YES |
$vars |
YES |
YES |
_vars |
YES |
$now / $today |
YES |
YES |
YES |
YES |
$execution |
YES |
YES |
_execution |
YES |
$workflow |
YES |
YES |
_workflow |
YES |
$prevNode |
YES |
YES |
YES |
YES |
$response |
NO |
NO |
NO |
YES |
$pageCount |
NO |
NO |
NO |
YES |
$parameter |
YES |
YES |
YES |
YES |
$ifEmpty() |
YES |
YES |
YES |
YES |
$jmespath() |
YES |
YES |
_jmespath() |
YES |
$getWorkflowStaticData() |
YES |
YES |
_getWorkflowStaticData() |
YES |
$execution.customData |
YES |
YES |
_execution |
YES |
Decision Tree: Expression Not Working
Expression returns unexpected result
|
+-- Is the variable available in this context?
| +-- NO --> Check Variable Availability Matrix above
| +-- YES --> Continue
|
+-- Does the field exist on the item?
| +-- Check with: {{ Object.keys($json) }}
| +-- Field missing --> Fix field name or check upstream node output
| +-- Field exists --> Continue
|
+-- Is the value null/undefined/empty?
| +-- YES --> Use $ifEmpty($json.field, fallback)
| +-- NO --> Continue
|
+-- Is the type correct?
| +-- String where number expected --> Number($json.field)
| +-- Number where string expected --> String($json.field)
| +-- String where date expected --> $json.field.toDateTime()
| +-- Type is correct --> Continue
|
+-- Is item linking the problem?
| +-- "Paired item not found" error --> See Paired Item Errors below
| +-- Wrong item data --> Use explicit .first()/.all() instead of .item
| +-- Correct linking --> Check expression syntax
Paired Item Error Resolution
When you see "Paired item not found" or get wrong data from $("<Node>").item:
- Identify the break point — Item linking breaks when a node changes item count (e.g., aggregation, split, filter removes items).
- Use explicit access instead:
$("<Node>").first() — ALWAYS returns first item (safe fallback)
$("<Node>").all()[index] — Access by position
$("<Node>").itemMatching(currentIndex) — Trace back from current item (preferred in Code node)
- In Code node — NEVER use
$("<Node>").item. ALWAYS use $("<Node>").itemMatching(index).
JMESPath Parameter Order
n8n uses $jmespath(object, searchString) — this is the OPPOSITE of the JMESPath spec's search(searchString, object).
// CORRECT — object first, search string second
{{ $jmespath($json.data, "[*].name") }}
// WRONG — search string first (JMESPath spec order)
{{ $jmespath("[*].name", $json.data) }}
ALWAYS verify: first argument is the data object, second argument is the query string.
Static Data Pitfalls
$getWorkflowStaticData() has specific constraints:
- NOT available during manual test execution — returns empty object
{}
- ONLY populated when workflow runs via trigger/webhook in production
- Data persists across executions but ONLY after successful completion
- NEVER store large data — keep static data small (IDs, timestamps, counters)
- May be unreliable during high-frequency parallel executions
Common Error Messages Reference
| Error Message |
Meaning |
Resolution |
Expression evaluation error |
Generic expression parse failure |
Check syntax: matching {{ }}, valid JS |
Cannot read properties of undefined (reading 'X') |
Accessing property on null/undefined |
Add null checks: $json.parent?.child |
X is not a function |
Wrong method for data type |
Check type: strings have .extractEmail(), arrays have .average() |
Paired item information is missing |
Item link chain broken |
Use .first(), .all(), or .itemMatching() |
ReferenceError: $itemIndex is not defined |
Used in Code node |
Use loop index or items.indexOf(item) |
ReferenceError: $secrets is not defined |
Used in Code node |
Use $env or pass via Set node |
Invalid left-hand side in assignment |
Assignment = inside expression |
Expressions are read-only; use Code node for assignment |
Unexpected token |
Syntax error in expression |
Check for unmatched brackets, quotes, or template literals |
Code Node Specific Restrictions
ALWAYS remember these restrictions when writing Code node logic:
$itemIndex — NOT available. Use loop index or items.indexOf(item).
$secrets — NOT available. Use $env.SECRET_NAME instead.
$("<Node>").item — NOT recommended. Use $("<Node>").itemMatching(index).
- No HTTP requests — use HTTP Request node before/after Code node.
- No file system access — use Read/Write Files nodes.
- Python: ALWAYS use bracket notation
item["json"]["field"], NEVER dot notation.
- Python on Cloud: NEVER import external libraries.
$response Context Restriction
$response is ONLY available in HTTP Request node parameter fields:
| Property |
Returns |
Context |
$response.body |
Response body object |
HTTP Request node ONLY |
$response.headers |
Response headers |
HTTP Request node ONLY |
$response.statusCode |
HTTP status code |
HTTP Request node ONLY |
$response.statusMessage |
Status message |
HTTP Request node ONLY |
If you need HTTP response data in other nodes, the HTTP Request node automatically outputs the response as $json for downstream nodes.
Null/Undefined Handling Strategy
ALWAYS handle potentially missing data with one of these approaches:
$ifEmpty(value, fallback) — Best for simple fallback values
- Optional chaining —
$json.parent?.child?.value for nested access
- Ternary —
{{ $json.field ? $json.field : "default" }} for conditional logic
- IIFE for complex logic:
{{ (function() {
const val = $json.field;
if (val === null || val === undefined) return "N/A";
return val.toString();
})() }}
Type Conversion Quick Reference
| From |
To |
Method |
| String |
Number |
Number($json.field) or parseInt() / parseFloat() |
| String |
Boolean |
$json.field.toBoolean() |
| String |
DateTime |
$json.field.toDateTime() |
| Number |
String |
String($json.field) or $json.field.format() |
| Number |
Boolean |
$json.field.toBoolean() (0 = false, else true) |
| Number |
DateTime |
$json.field.toDateTime() (Unix ms or seconds) |
| Boolean |
Number |
$json.field.toNumber() (true=1, false=0) |
| Boolean |
String |
$json.field.toString() |
| Array |
String |
$json.arr.toJsonString() |
| Object |
String |
$json.obj.toJsonString() |
Reference Files
- references/methods.md — Expression error types and variable availability details
- references/examples.md — Common expression errors with before/after fixes
- references/anti-patterns.md — Expression anti-patterns to avoid
1---2name: n8n-errors-expressions3description: Use when debugging expression evaluation failures or undefined references in n8n workflows. Prevents data access errors by mapping every expression variable to its valid context. Covers undefined $json references, type mismatches, missing paired items, $itemIndex unavailability in Code node, $secrets restriction in Code node, JMESPath parameter order confusion, empty expression results, and context-dependent variable availability. Keywords: n8n, expression, error, $json, variable, type mismatch, expression error, undefined value, variable not found, wrong type, empty result..4license: MIT5---67# n8n Expression Error Diagnosis89> Diagnose and fix expression evaluation failures in n8n v1.x workflows.10> For error type details see [references/methods.md](references/methods.md).11> For before/after fixes see [references/examples.md](references/examples.md).12> For anti-patterns see [references/anti-patterns.md](references/anti-patterns.md).1314---1516## Quick Diagnostic Table1718| Symptom | Cause | Fix |19|---------|-------|-----|20| `undefined` when accessing `$json.field` | Field does not exist on current item | Check field name spelling; use `$json?.field` or `$ifEmpty($json.field, fallback)` |21| `TypeError: Cannot read properties of undefined` | Accessing nested field on null/undefined parent | Chain optional access: `$json.parent?.child?.value` |22| `$itemIndex is not defined` in Code node | `$itemIndex` is NOT available in Code node | Use `items.indexOf(item)` or loop index variable instead |23| `$secrets is not defined` in Code node | `$secrets` is NOT available in Code node | Use `$env.SECRET_NAME` or pass secret via preceding Set node |24| `$response is not defined` | `$response` used outside HTTP Request node | ONLY use `$response` in HTTP Request node parameter fields |25| `Paired item not found` | Item linking broken between nodes | Use `$("<Node>").first()` or `$("<Node>").all()[index]` instead of `.item` |26| JMESPath returns unexpected result | Parameter order swapped | ALWAYS use `$jmespath(object, searchString)` — object first, search second |27| Expression returns empty string | Field exists but value is `null`, `""`, or `undefined` | Use `$ifEmpty($json.field, "default")` to provide fallback |28| `$getWorkflowStaticData` returns empty | Static data not available during manual test | ALWAYS test static data with active workflow (webhook/trigger), NEVER manual execution |29| `TypeError: X is not a function` | Calling n8n extension method on wrong type | Verify data type: `.extractEmail()` requires string, `.average()` requires array |30| `$("<Node>").item` returns wrong data | Expression evaluated in non-matching context | Use `$("<Node>").itemMatching(index)` in Code node; use `.first()` or `.all()` for explicit access |31| Python `AttributeError` on item access | Using dot notation in Python Code node | ALWAYS use bracket notation: `item["json"]["field"]` |32| `$pageCount is not defined` | Used outside HTTP Request node pagination | `$pageCount` is ONLY available in HTTP Request node |33| Number treated as string in comparison | n8n expression returned string type | Explicitly convert: `Number($json.price)` or use `parseInt()`/`parseFloat()` |34| Date comparison fails | Comparing string dates instead of DateTime | Convert with `.toDateTime()` then compare with `.diffTo()` or `.isBetween()` |3536---3738## Variable Availability Matrix3940Use this matrix to determine which variables are available in each context.4142| Variable | Expression Fields | Code Node (JS) | Code Node (Python) | HTTP Request Node |43|----------|:-:|:-:|:-:|:-:|44| `$json` / `$binary` | YES | YES | `_json` / `_binary` | YES |45| `$input.item` | YES | YES (each-item mode) | `_item` | YES |46| `$input.all()` | YES | YES | `_items` | YES |47| `$("<Node>").item` | YES | NO (use `.itemMatching()`) | NO | YES |48| `$("<Node>").itemMatching()` | YES | YES | YES (`_("<Node>")`) | YES |49| `$itemIndex` | YES | **NO** | **NO** | YES |50| `$runIndex` | YES | YES | YES | YES |51| `$secrets` | YES | **NO** | **NO** | YES |52| `$env` | YES | YES | `_env` | YES |53| `$vars` | YES | YES | `_vars` | YES |54| `$now` / `$today` | YES | YES | YES | YES |55| `$execution` | YES | YES | `_execution` | YES |56| `$workflow` | YES | YES | `_workflow` | YES |57| `$prevNode` | YES | YES | YES | YES |58| `$response` | NO | NO | NO | **YES** |59| `$pageCount` | NO | NO | NO | **YES** |60| `$parameter` | YES | YES | YES | YES |61| `$ifEmpty()` | YES | YES | YES | YES |62| `$jmespath()` | YES | YES | `_jmespath()` | YES |63| `$getWorkflowStaticData()` | YES | YES | `_getWorkflowStaticData()` | YES |64| `$execution.customData` | YES | YES | `_execution` | YES |6566---6768## Decision Tree: Expression Not Working6970```71Expression returns unexpected result72|73+-- Is the variable available in this context?74| +-- NO --> Check Variable Availability Matrix above75| +-- YES --> Continue76|77+-- Does the field exist on the item?78| +-- Check with: {{ Object.keys($json) }}79| +-- Field missing --> Fix field name or check upstream node output80| +-- Field exists --> Continue81|82+-- Is the value null/undefined/empty?83| +-- YES --> Use $ifEmpty($json.field, fallback)84| +-- NO --> Continue85|86+-- Is the type correct?87| +-- String where number expected --> Number($json.field)88| +-- Number where string expected --> String($json.field)89| +-- String where date expected --> $json.field.toDateTime()90| +-- Type is correct --> Continue91|92+-- Is item linking the problem?93| +-- "Paired item not found" error --> See Paired Item Errors below94| +-- Wrong item data --> Use explicit .first()/.all() instead of .item95| +-- Correct linking --> Check expression syntax96```9798---99100## Paired Item Error Resolution101102When you see "Paired item not found" or get wrong data from `$("<Node>").item`:1031041. **Identify the break point** — Item linking breaks when a node changes item count (e.g., aggregation, split, filter removes items).1052. **Use explicit access instead:**106 - `$("<Node>").first()` — ALWAYS returns first item (safe fallback)107 - `$("<Node>").all()[index]` — Access by position108 - `$("<Node>").itemMatching(currentIndex)` — Trace back from current item (preferred in Code node)1093. **In Code node** — NEVER use `$("<Node>").item`. ALWAYS use `$("<Node>").itemMatching(index)`.110111---112113## JMESPath Parameter Order114115n8n uses `$jmespath(object, searchString)` — this is the OPPOSITE of the JMESPath spec's `search(searchString, object)`.116117```js118// CORRECT — object first, search string second119{{ $jmespath($json.data, "[*].name") }}120121// WRONG — search string first (JMESPath spec order)122{{ $jmespath("[*].name", $json.data) }}123```124125ALWAYS verify: first argument is the data object, second argument is the query string.126127---128129## Static Data Pitfalls130131`$getWorkflowStaticData()` has specific constraints:132133- **NOT available during manual test execution** — returns empty object `{}`134- ONLY populated when workflow runs via trigger/webhook in production135- Data persists across executions but ONLY after successful completion136- NEVER store large data — keep static data small (IDs, timestamps, counters)137- May be unreliable during high-frequency parallel executions138139---140141## Common Error Messages Reference142143| Error Message | Meaning | Resolution |144|---------------|---------|------------|145| `Expression evaluation error` | Generic expression parse failure | Check syntax: matching `{{ }}`, valid JS |146| `Cannot read properties of undefined (reading 'X')` | Accessing property on null/undefined | Add null checks: `$json.parent?.child` |147| `X is not a function` | Wrong method for data type | Check type: strings have `.extractEmail()`, arrays have `.average()` |148| `Paired item information is missing` | Item link chain broken | Use `.first()`, `.all()`, or `.itemMatching()` |149| `ReferenceError: $itemIndex is not defined` | Used in Code node | Use loop index or `items.indexOf(item)` |150| `ReferenceError: $secrets is not defined` | Used in Code node | Use `$env` or pass via Set node |151| `Invalid left-hand side in assignment` | Assignment `=` inside expression | Expressions are read-only; use Code node for assignment |152| `Unexpected token` | Syntax error in expression | Check for unmatched brackets, quotes, or template literals |153154---155156## Code Node Specific Restrictions157158ALWAYS remember these restrictions when writing Code node logic:1591601. `$itemIndex` — **NOT available**. Use loop index or `items.indexOf(item)`.1612. `$secrets` — **NOT available**. Use `$env.SECRET_NAME` instead.1623. `$("<Node>").item` — **NOT recommended**. Use `$("<Node>").itemMatching(index)`.1634. No HTTP requests — use HTTP Request node before/after Code node.1645. No file system access — use Read/Write Files nodes.1656. Python: ALWAYS use bracket notation `item["json"]["field"]`, NEVER dot notation.1667. Python on Cloud: NEVER import external libraries.167168---169170## $response Context Restriction171172`$response` is ONLY available in HTTP Request node parameter fields:173174| Property | Returns | Context |175|----------|---------|---------|176| `$response.body` | Response body object | HTTP Request node ONLY |177| `$response.headers` | Response headers | HTTP Request node ONLY |178| `$response.statusCode` | HTTP status code | HTTP Request node ONLY |179| `$response.statusMessage` | Status message | HTTP Request node ONLY |180181If you need HTTP response data in other nodes, the HTTP Request node automatically outputs the response as `$json` for downstream nodes.182183---184185## Null/Undefined Handling Strategy186187ALWAYS handle potentially missing data with one of these approaches:1881891. **`$ifEmpty(value, fallback)`** — Best for simple fallback values1902. **Optional chaining** — `$json.parent?.child?.value` for nested access1913. **Ternary** — `{{ $json.field ? $json.field : "default" }}` for conditional logic1924. **IIFE for complex logic:**193 ```js194 {{ (function() {195 const val = $json.field;196 if (val === null || val === undefined) return "N/A";197 return val.toString();198 })() }}199 ```200201---202203## Type Conversion Quick Reference204205| From | To | Method |206|------|----|--------|207| String | Number | `Number($json.field)` or `parseInt()` / `parseFloat()` |208| String | Boolean | `$json.field.toBoolean()` |209| String | DateTime | `$json.field.toDateTime()` |210| Number | String | `String($json.field)` or `$json.field.format()` |211| Number | Boolean | `$json.field.toBoolean()` (0 = false, else true) |212| Number | DateTime | `$json.field.toDateTime()` (Unix ms or seconds) |213| Boolean | Number | `$json.field.toNumber()` (true=1, false=0) |214| Boolean | String | `$json.field.toString()` |215| Array | String | `$json.arr.toJsonString()` |216| Object | String | `$json.obj.toJsonString()` |217218---219220## Reference Files221222- [references/methods.md](references/methods.md) — Expression error types and variable availability details223- [references/examples.md](references/examples.md) — Common expression errors with before/after fixes224- [references/anti-patterns.md](references/anti-patterns.md) — Expression anti-patterns to avoid