← n8n Errors|Debugalo

n8n Error Reference

n8n expression returned undefined

This error fires when an n8n expression references a field that doesn't exist at the expected path in the upstream payload. The expression evaluates to undefined, and any downstream property access on that undefined value throws a TypeError.

Quick Diagnosis

Open the failed node → click the Input tab → find the field your expression references. If it's missing or nested one level deeper than expected, the problem is the path in your expression, not the node itself.

Error variants

Undefined expression errors surface in several forms depending on where the undefined value is consumed:

ERROR: Expression returned undefined
The expression evaluated cleanly but returned undefined because the referenced field doesn't exist in the runtime payload. n8n surfaces this as an expression error rather than a TypeError. The field is either missing, at a different nesting level, or the upstream node returned no items.
TypeError: Cannot read properties of undefined (reading 'email')
The expression first resolved a parent field to undefined, then tried to read a child property from it. For example, $json.customer is undefined, and the expression then accesses .email on it. Fix the parent path first.
Expression result: undefined (shown in expression editor preview)
The expression editor shows undefined in the preview pane before execution. This means the path is already wrong relative to the sample data loaded in the editor. Expand the data panel on the left side of the editor to inspect the actual field structure.
Node output is empty / items: 0
A Filter, If, or HTTP node upstream returned zero items. The downstream node receives no input, so every $json reference evaluates to undefined. This is a data flow issue, not an expression syntax issue.

What this error means

n8n evaluates expressions at runtime against the actual data flowing through the workflow. When an expression like {{ $json.customer.email }} runs, n8n walks the payload object key by key — first looking for customer, then email inside it. If customer doesn't exist at that path, the lookup returns undefined. If customer exists but email is missing from it, same result. The expression doesn't throw immediately — it silently returns undefined. The error surfaces when something downstream tries to use that undefined value: inserting it into a field that requires a string, passing it to a node that expects an object, or accessing another property from it.

Common causes

1

Webhook payload nested under body

n8n webhook nodes wrap the incoming request body under a body key. An expression referencing $json.customer.email fails when the actual path is $json.body.customer.email. This is one of the most common undefined errors in webhook-triggered workflows. Open the Output tab of the Webhook node and check whether your fields are nested under body before writing any downstream expression.

2

Array index on an empty array

An expression like $json.orders[0].id returns undefined when orders exists but has no items. The array is present in the payload, but index 0 doesn't exist. Add an If node before the expression to check $json.orders.length > 0 and route empty arrays to a separate branch.

3

AI node returning a different output shape

LLM and AI nodes don't always return the same field names. An expression expecting $json.sentiment.score fails when the AI node returns $json.result.sentimentScore or $json.output instead. Open the Output tab of the AI node after a real execution and read the actual field names before writing any downstream expression.

4

HTTP Request node returning an error payload

When an external API returns a 4xx or 5xx response, the response body is often an error object rather than the expected data structure. An expression that works for successful responses returns undefined on error responses because the expected fields don't exist in the error envelope. Add a check on $json.error or the HTTP status code before passing the response downstream.

5

Optional field absent on some records

The field exists on most records but is omitted entirely on others — a database NULL, an optional API field, or a conditional webhook property. The workflow succeeds most of the time and fails intermittently. Add a fallback: {{ $json.notes ?? '' }} returns an empty string instead of undefined when the field is missing.

6

Wrong node reference in the expression

An expression uses $("Node Name").item.json.field but references the wrong node name, or the node was renamed after the expression was written. n8n silently returns undefined for unresolvable node references. Check the exact name of the upstream node and confirm it matches the string in the expression.

How to diagnose it

  1. 1

    Open the failed execution and click the red failed node. Select the Input tab — this shows exactly what data the node received at runtime.

  2. 2

    Find the field path your expression references. Expand every nested level. If the field is missing entirely, the problem is upstream — check the Output tab of the previous node.

  3. 3

    If the field exists but at a different nesting level, update the expression path. A single extra or missing key like body or data is enough to return undefined on every execution.

  4. 4

    For webhook workflows: check whether your fields are nested under body in the Webhook node output. If so, update all downstream expressions to include body in the path.

  5. 5

    For AI node outputs: run the workflow once with a real input and inspect the actual Output tab of the AI node. Do not assume the output shape — read it directly.

  6. 6

    Use the expression editor preview pane to validate the path before saving. If the preview shows undefined, the path is wrong relative to the sample data.

  7. 7

    For intermittent undefined errors: add an If node before the failing node to check the field exists ({{ $json.fieldName !== undefined }}) and route the missing-field case to a Stop And Error node or a fallback branch.

n8n-specific scenarios

customer.email missing — webhook body wrapper

An expression reads $json.customer.email but the webhook payload is structured as { body: { customer: { email: '...' } } }. The field exists — it's just nested under body. The correct expression is $json.body.customer.email. Open the Webhook node Output tab and look for the body key wrapping all incoming fields. Every expression in a webhook-triggered workflow likely needs the body prefix added.

orders[0].id — empty array at runtime

A search or database node returns { orders: [] } when no results match. A downstream expression reads $json.orders[0].id, which returns undefined because index 0 doesn't exist on an empty array. Add an If node after the search node: route the empty-orders case ({{ $json.orders.length === 0 }}) to a separate branch that handles the no-results scenario explicitly.

sentiment.score — AI node output mismatch

A workflow sends text to an AI node expecting it to return { sentiment: { score: 0.9 } }. The AI node returns { result: 'positive', confidence: 0.9 } instead. The expression $json.sentiment.score returns undefined because the AI didn't use the expected field names. Always inspect the actual AI node output after a live execution before writing downstream expressions. Use $json.confidence instead of $json.sentiment.score in this case.

Paste your full error message and the failed node's output into Debugalo to get a structured breakdown: the exact failed step, root cause, and concrete fix steps.

Analyze this error →

FAQ

How do I write a safe expression that handles a missing field?

Use optional chaining and a nullish coalescing fallback: {{ $json.customer?.email ?? '' }}. The ?. stops evaluation and returns undefined if customer is missing, and ?? '' replaces that undefined with an empty string. This prevents the TypeError without masking the missing data — you'll see an empty value in the output instead of a broken execution.

Why does the expression work in the editor preview but fail at runtime?

The expression editor loads sample data from a previous execution. If that previous execution had a different payload shape — for example, it had the field but the current run doesn't — the preview shows a valid result while the live execution returns undefined. Always test with a representative payload that matches the edge case causing the error.

How do I check the actual payload shape in n8n without running the whole workflow?

Pin the data on the upstream node. Right-click the node → Pin Data → paste or enter example data that matches your real input. The downstream expression editor will use that pinned data for its preview. This lets you test expressions against specific payloads, including empty arrays and missing fields, without triggering the full workflow.

My webhook expression worked before and now returns undefined. What changed?

Either the incoming webhook payload structure changed — the sender added or removed a wrapper level — or an upstream node was renamed and the expression reference no longer resolves. Check the Input tab of the failing node in the most recent broken execution and compare it to an older successful execution. The difference in the data structure is the cause.

Can I add a fallback value directly in the expression?

Yes. {{ $json.orders?.[0]?.id ?? 'no-order' }} returns 'no-order' when orders is empty or missing. The ?. before [0] prevents the TypeError when orders is undefined. The ?? operator catches both undefined and null. Use specific fallback values that make sense for the downstream node — an empty string, a default ID, or a sentinel value your If node can route on.

Related Guides