Debugging an n8n workflow: the complete method, from failed execution to tested fix
Published 28 July 2026 · 7 min read
A workflow failing in production doesn't get fixed by rereading its nodes one by one, hoping to spot the mistake. n8n ships everything you need to debug methodically — a detailed execution history, replay with the original data, data pinning, node-by-node execution — but these tools are scattered across the interface and rarely used together. This guide assembles them into a single method: reproduce → isolate → fix → retest with the same data. Each step maps to a specific n8n feature, and the order matters.
Start by reading the failed execution, not the workflow
The first reflex is to open the executions list (the Executions tab, at the workflow level or across the whole instance) and filter on failures. Opening a failed execution shows the workflow as it actually ran: the nodes that succeeded, and the failing node marked in red.
Clicking that node reveals three things, to be read in order:
- the error message, often enough on its own (missing field, HTTP 401/429/500, expired credential);
- the stack or technical details, useful when the message is generic — that's where an HTTP error code or the API's response body hides;
- the node's input data, because the error comes from the incoming data at least as often as from the node's own configuration. A perfectly configured HTTP Request node will still fail if the incoming item carries an
undefinedwhere the URL expects an identifier.
Research backs up this reflex: Parnin and Orso's study presented at ISSTA 2011, "Are Automated Debugging Techniques Actually Helping Programmers?" (see on Google Scholar), shows that developers don't linearly follow a tool-provided list of "suspicious lines": what moves the diagnosis forward is understanding the execution context. Translated to n8n: the red node tells you where it broke, but the input data and the chain of preceding nodes tell you why.
Reproduce: replay with the same data
Fixing without being able to reproduce the failure is fixing blind. n8n lets you copy the data from a past execution into the editor: from the failed execution, the replay feature ("Debug in editor" on recent versions) pins that execution's data onto the nodes in the editor. You're now working with the exact dataset that caused the failure — Tuesday's 3am webhook payload, not an example rebuilt from memory.
This is especially valuable for workflows triggered by external events that are hard to re-trigger: a Stripe webhook, an incoming email, a form submission. For webhooks in particular, this replay pairs well with the techniques in our guide to testing n8n webhooks locally.
Isolate: Pin Data and node-by-node execution
Once the failure is reproducible, narrow the search area. Two tools:
Pinning data (Pin Data). Pinning a node's output freezes its result: on subsequent manual runs, n8n reuses the pinned data instead of re-executing the node. Pin the output of the last healthy node, and you can iterate on the broken section without calling the upstream APIs again — no quota burned, no latency, no side effects. Worth remembering: pins only apply to manual executions, never in production, so they're harmless to your real runs.
Running node by node. Rather than rerunning the whole workflow, execute only the suspect node (or the subset up to it). Combined with pinning, this turns debugging into a tight loop: change the node, run it alone, read its output, repeat. Ten iterations take two minutes instead of twenty.
Inspect the data between two nodes
Between every pair of nodes, the data panel offers three complementary views:
- Table — quick scan of items and spotting empty or shifted fields;
- JSON — the exact structure, essential for writing an expression with the right access path;
- Schema — the field tree, the most efficient way to check that a path exists before referencing it in an expression.
The right question at this stage isn't "what's broken?" but "why did this node receive this data, and why not the data I expected?". Ko and Myers formalized this approach in "Debugging Reinvented" (ICSE 2008 — see on Google Scholar): effective debugging means answering "why" and "why not" questions about observed behavior, rather than inspecting state at random. n8n's data panel is exactly the tool that answers those questions, node by node.
The classic expression errors
Most workflow bugs are expression errors. The four most frequent:
undefined: the path doesn't exist in the current item — misspelled field, different nested structure, or a referenced node that never ran on that branch. Check the path in the Schema view rather than typing it from memory.[Object: object]: you're inserting a whole object where a string is expected. Go one level deeper ({{ $json.client.email }}instead of{{ $json.client }}) or serialize withJSON.stringify().- item vs items: in a Code node, the "Run Once for All Items" mode exposes an
itemsarray to loop over, while "Run Once for Each Item" processes one item at a time. Treating one like the other yields empty results, or a single item where you expected a hundred. $jsonvs$('Node').item.json:$jsonrefers to the current node's immediate input; to read an earlier node in the chain, you have to name it explicitly. Be careful with item pairing, though, when intermediate nodes have merged or filtered the data.
For a solid foundation on these mechanisms, see our guide to JavaScript expressions and the Code node.
Test the error branches, not just the happy path
A robust workflow plans for failure: the Continue On Fail option (or a dedicated error output, depending on the version) on critical nodes, routing failed items to a handling branch, and an Error Workflow for global failures. These branches deserve testing like everything else: deliberately force an error (invalid URL, removed credential, required field deleted from the pinned data) and verify the error branch behaves as intended. For transient API errors, configuring retry and timeout on HTTP Request nodes prevents plenty of error branches from firing for nothing. And if the failing node is an AI agent, the symptoms have their own causes — our article on AI Agent node errors walks through them.
When the UI isn't enough: server logs
Some problems leave no trace in the executions list: a worker crash, an out-of-memory kill that ends the execution before it's saved, a webhook rejected before an execution is even created, a database connection error. That's when you head for the server logs:
docker logs -f your-n8n-container-name
Verbosity is controlled with the N8N_LOG_LEVEL environment variable (info by default, debug for a one-off diagnosis — don't leave it on permanently, the output volume quickly becomes unmanageable). On a serious instance, these signals deserve continuous collection rather than after-the-fact reading: that's the subject of our guide to monitoring an n8n instance.
A word about the browser console: it's almost always useless for debugging a workflow. Workflows run server-side; the console only sees the editor's interface. It only helps in the rare cases where the editor itself misbehaves (a canvas that won't load, a rendering error) — never for understanding why a node fails.
Retest with the same data, then widen
Fix applied, replay with the pinned data from the failed execution: if it passes, the specific bug is fixed. Then widen: unpin and rerun with fresh data to confirm the fix holds against the real API, and test one or two neighboring cases (empty item, missing optional field, batch of several items). For AI workflows whose output varies from run to run, this retest is worth systematizing — that's exactly what AI workflow evaluations are for.
Common pitfalls
- Fixing without reproducing. Changing a node on the strength of the error message alone, rerunning with data different from the failure's, and believing the bug fixed because "it passes" — while the failing case was never replayed.
- Forgetting stale pinned data. A pin that predates a format change on the API side makes all your manual tests pass while production keeps failing. Systematically unpin at the end of a debugging session.
- Searching inside the red node when the fault is upstream. The failing node is often the victim: an earlier node produced an empty field or the wrong type, and the error only surfaces two nodes later. Walk back up the chain with the Schema view.
- Debugging in production. Manually running a workflow wired to real APIs during diagnosis can send real emails or create real invoices. Pin the input data and disable or isolate side-effect nodes for the duration of the debugging.
- Confusing an execution error with an infrastructure error. If the execution doesn't even appear in the list, there's no point searching inside the workflow: the problem sits upstream (webhook, reverse proxy, memory, database) and shows up in the server logs.
Going further
The reproduce → isolate → fix → retest method covers one-off debugging; at the scale of an instance running for real clients, the question becomes: what happened, when, and on which data? The Compliance & Audit Pack (€149) provides the logging and traceability workflows that keep a usable record of every execution — precisely what's missing when debugging turns into an audit, three weeks after the fact, on an execution the retention policy has already purged. As a complement, the Error Workflow turns every future failure into an immediate notification rather than a late discovery in the executions list.
FAQ
Frequently asked questions
How do I replay a failed n8n execution with exactly the same data?
Open the failed execution from the executions list, then use the copy-to-editor feature (Debug in editor on recent versions): n8n pins the data from the past execution onto the nodes in the editor. You can then rerun the workflow as many times as needed with the exact dataset that actually caused the failure, without depending on a new external event. That's the difference between fixing blind and fixing verifiably.
What is Pin Data for in n8n, and what are its limits?
Pinning a node's output data freezes that result: on subsequent manual runs, n8n reuses the pinned data instead of re-executing the node. It's ideal for iterating on the rest of the workflow without calling a paid, slow or rate-limited API again. Two limits: pins only apply to manual executions (never in production), and stale pinned data can hide a format change on the API side.
Why does my n8n expression return undefined or [Object: object]?
An undefined almost always means the requested path doesn't exist in the current item: a misspelled field, a nested structure different from what you expected, or a reference to a node that never ran on that branch. An [Object: object] means you're inserting a whole object where a string is expected: go one level deeper into the structure or serialize with JSON.stringify. The Schema view in the data panel lets you verify the exact path in one click.
Where do I find n8n's server logs and how do I make them more verbose?
On a Docker install, docker logs followed by the container name prints the n8n process output; add -f to follow it in real time. Verbosity is controlled by the N8N_LOG_LEVEL environment variable (info by default, debug for diagnosis). These logs cover what the UI doesn't show: worker crashes, out-of-memory kills, database connection errors, or webhook problems that occur before an execution even exists.
Bundle FlowKit Complet
€269