← n8n Production Guides

GUIDE · Data & Expressions

n8n “Cannot Read Properties of Undefined”: The Definitive Fix

2026-10-25 · William Ayad · 10 min read

In one sentence: a node tried to read a property from a value that does not exist — in this execution's data, at that path. The property name in parentheses (reading 'name', reading '0',reading 'json') is the exact segment where the path went dark. The error is not random, not a platform bug (despite years of community threads suggesting otherwise), and not fixed by reconnecting anything. It is a data-shape report. There are five reasons a path goes dark, and each has a correct, permanent fix. This guide walks all five, then the guard patterns that make the failure structurally impossible instead of merely absent this week.

Zero: read it like a report, ten seconds

Three facts are embedded in every occurrence: the property name — what n8n was reaching for when it hit the void; the node — the red node in the failed execution did the reaching (the void usually lives upstream of it); and the run — intermittent failures mean the void only exists forsome inputs. Hold those three; every cause below is one of them going wrong in a specific way. And a naming note that saves half the confusion: Cannot read properties of undefined (the field does not exist) and ...of null (the field exists as an explicit no-value, typically SQL NULL) are sibling failures with the same fix patterns.

Cause 1 — The upstream node returned nothing

An If node sent everything down the other branch. A Filter matched zero items. A database read found no rows. Downstream, your node evaluates $json.customer.email — and there is no $json at all, because there are no items. This is the most misdiagnosed cause, because the failing node looks guilty while being innocent. Verify in ten seconds: the failing node's Input panel is empty, or the node immediately before it shows zero output items. The fix is never inside the red node; it is handling the zero-items case before it arrives.

Cause 2 — The path is one nesting level off

The data exists — one level deeper than the expression reaches. $json.items when reality is $json.data.items; $json.text when the AI node produced $json.message.text. Everyone who has built three n8n workflows has typed the shorter one from memory. The evidence-safe habit, straight from the field playbook: stop typing paths — drag them. Pull the field from the Input schema panel into the expression field and let n8n construct the correct path, every time, including past schemas you have not memorized and keys you would have misquoted.

Cause 3 — A renamed (or skipped) node reference

$node["Get_Customers"] does not update itself when you rename the node to Get Customers v2; the expression now references a node that has never existed and voids at runtime. The shyer sibling: a node reference that is spelled correctly but points at a node that did not run in this execution — a skipped branch, a de-duplicated trigger — so it has no output to reference. Both collapse into the same error text. Grep every expression after every rename, and prefer the $json / immediate-input style of reference for data that flows linearly: it cannot rot under renaming, because it never names anyone.

Cause 4 — The API's shape moved (or wobbles per record)

The integration that failed on exactly one record in ten thousand: the provider omits optional fields when empty (middle_name exists for 99.9% of users, not for that one), a NULL slipped in from a SQL source, or the API shipped a v2-shaped answer after an "upgrade we didn't hear about". The failure is intermittent precisely because the data is. The triage habit: pin the failing execution, open the input, and ask "where is the property from the error text?" — absent-on-this-record is the answer in hand. When a version bump is suspect, the error-codes map helps separate data-shape deaths from the authentication ones that updates also trigger.

Cause 5 — The unquotable key

$json.row id and $json.user.name.csv — keys containing spaces, hyphens, or dots cannot be reached by dot notation at all; the first dot ends the parse. The key exists, humans can see it, and the expression still returns undefined. The door in is bracket notation with the exact key: $json["row id"]. Dragging from the input panel generates precisely this form when needed — one more reason Cause 2's habit pays for itself.

The post-update variant of all five

A wave of "undefined" complaints arrives right after upgrades, and the mechanism is usually fieldremoval, not new bugs: a Set/Edit Fields node whose defaults changed, the "Keep Only Set Fields" behavior stripping every key you did not explicitly pass through, or a node whose output schema got reorganized by design. The tell is ubiquity — the error lands on every execution, not some — and the four-minute ritual above still applies — just now against the new shape. Diff the node's output before and after the version change and the missing key steps forward on its own.

The guard patterns (make it impossible, not unlikely)

Fix causes; guard so the whole class dies. Four patterns cover essentially every production variant:

Choose on one axis: expressions for reading-optional fields, If-gates for workflow-legitimately-empty cases, Code guards for array math, Stop-and-Error for "this should never happen and we want the page".

The four-minute debugging session, on rails

When the alert lands, run this exact sequence — it converts an open-ended hunt into a deterministic one:

  1. Pin the failing execution (or re-run with the same input), so the evidence cannot drift while you look at it.
  2. Copy the property name out of the parentheses — that string is the search term for everything that follows.
  3. Open the red node's Input panel and expand every level; find that exact key. Absent entirely → Cause 1 or 4. Present one level deeper → Cause 2. Present but null → the null sibling of Cause 4.
  4. If the Input panel is empty, walk upstream node-by-node until output reappears; the gap is where the items vanished, and the red node was only reporting it.
  5. Install the matching guard at the gap, unpin, replay, and confirm the empty-case branch behaves the way you intended — before anyone thanks you.

Intermittent cases add one step before pin-and-replay: capture the failing record's source payload (the upstream node's output for that item), because next week's run may succeed and carry the evidence away.

Classify your exact text in two seconds, then fix

Which of the five causes is yours is a classification question — and classification of known crash text is exactly what the free n8n Error Doctor does: paste the execution's error text and it answers with the matched class, the underlying cause, and the fix pattern in about two seconds, entirely in your browser. For the rarer disappointment — a workflow whose structural traps (missing error branches, retries absent ahead of a flaky source) let data problems surface as undefined-path deaths downstream — the free workflow audit flags those structural suspects on the exported JSON. Honest boundary, stated plainly: a static export cannot reveal which runtime record lacked a field; that evidence only exists in your execution history — which is why the pin-and-inspect ritual above is in this guide at all.

For teams running many workflows: the pre-built layer

Scaling this discipline across dozens of workflows is where the n8n Reliability Kit earns its one-time $19 (disclosing: mine): the decision trees walk "undefined / null path errors" from symptom to the correct of the five causes interactively; the documented failure library carries this exact class with incidence context and prevention checklists; the 24-rule auditor flags the structural preconditions (unguarded fan-out after filters, retry-less upstream calls feeding expression chains); and the 34-point preflight turns "did we guard the empty case?" into a launch-day habit instead of a Friday-night discovery. Same browser-only architecture as the free tools — nothing you export ever leaves your machine.

Frequently asked questions

What does “Cannot read properties of undefined” mean in n8n?

A property was read from a value absent at that path in this execution. The parenthesized name is the failed segment. Five causes cover the field: empty upstream output, off-by-one nesting, renamed/unrun node references, provider shape drift (including per-record omissions), and unquotable keys.

Why does it only happen on some executions?

Because the input varies: optional fields absent on one record, a filter that matched nothing this run, a NULL from the database. The fix is the guard — handle the missing case deliberately before any node reads it, and intermittent becomes impossible.

Undefined vs null — does the difference matter?

Undefined: the field does not exist at that path. Null: it exists, explicitly emptied (SQL NULL, API null). Both throw the sibling TypeError; both die to the same existence guard (!== undefined and !== null).

Can an Error Trigger workflow replace all these guards?

No — they answer different questions. An error workflow catches failures after they happen (the right home for alerting and cleanup); guards prevent the class before it throws. Production wants both: guards so the ordinary missing-field case never error-pages anyone, and the error workflow so the genuinely novel failure arrives with context.

How do I see exactly what the node received this run?

Failed execution → red node → Input panel: that is the true payload. Compare every nesting level against the error's property name. In Code nodes, console.log(JSON.stringify($input.all())) prints the same truth to the execution log for re-runs.

The one-paragraph answer to bookmark

The error is a map reading, not a crash: some path's value was missing, and the name in parentheses tells you which segment. Confirm what the node really saw (Input panel, or a logged $input.all()), identify your cause among the five, then install the matching guard — existence gate, optional chaining with defaults, Code-node array guard, humane Stop-and-Error. Fix the node once; guard so the class never pages you again.

Holding the crash text right now?

Classify it in two seconds — browser-only, free, nothing uploaded.