n8n Debug Workflow
Diagnose failing n8n executions. Most n8n bugs fall into a handful of
categories — recognize the category, then apply the matching fix.
References: ERROR_CATALOG.md | EXECUTION_DEBUGGING.md | ITEM_LINKING_ERRORS.md | RATE_LIMITS.md | TRIGGER_PROBLEMS.md
Lessons: LESSONS_LEARNED.md — read before non-trivial work.
Authoritative docs: https://docs.n8n.io/courses/level-two/chapter-4/ (debugging chapter) and https://docs.n8n.io/flow-logic/error-handling/.
Triage in three questions
Before opening logs, get the user to answer three questions. They short-circuit
80% of debugging:
- Which node fails? Open the execution in the Editor → Executions tab.
Look for the red node. Errors propagate upstream visually — the actual
failure is the FIRST red node from the trigger.
- What's the exact error message? Copy it verbatim. n8n error messages
are usually accurate; the model + free-text reasoning is almost always
in the message.
- Did this work before? If yes — what changed? (Workflow edits, n8n
version upgrade, credential rotation, API change upstream, schedule
timezone shift.)
If the user can't answer #1 because no execution log exists (workflow
never fires), jump to Trigger never fires.
Error categories (load the matching reference)
| Symptom |
Category |
Reference |
| Node throws with API/transport error |
API errors |
ERROR_CATALOG.md |
"Could not find paired item" / $('X').item throws |
Item linking |
ITEM_LINKING_ERRORS.md |
| HTTP 429, ETIMEDOUT, ECONNRESET storms |
Rate limits |
RATE_LIMITS.md |
| "Cannot read properties of undefined" in expression |
Expression errors |
ERROR_CATALOG.md |
| Trigger doesn't fire / fires twice / fires late |
Trigger problems |
TRIGGER_PROBLEMS.md |
| Execution stalls or times out |
Execution problems |
EXECUTION_DEBUGGING.md |
| Memory/disk usage spikes during execution |
Execution problems |
EXECUTION_DEBUGGING.md |
| Webhook returns wrong status/body |
Webhook problems |
TRIGGER_PROBLEMS.md |
| Data is "missing" in a downstream node |
Item linking OR run-mode |
ITEM_LINKING_ERRORS.md, then EXECUTION_DEBUGGING.md |
Procedure (any debugging request)
Step 1 — Read the execution log
In the Editor:
- Open the workflow.
- Click the Executions tab.
- Open the failed execution.
- Click on the red (failed) node — the right panel shows input data,
output data, and the error.
- Click upstream nodes to verify they actually produced the data the
failed node expected.
Three things to extract:
- Error message (exact text, including the "On node X" prefix).
- Input data to the failing node — is it empty? Wrong shape?
- Output data of the immediately-upstream node — does it match what the
failing node was expecting?
Step 2 — Reproduce locally if possible
- Use Pin Data on the failing node: right-click → Pin (or set
pinData in workflow JSON). This lets you re-run downstream without
re-firing the trigger.
- Use the Run from this Node option (right-click on a node) to start
execution from a specific node using its pinned data.
- For Webhook-triggered workflows, replay the original request using the
Webhook node's "Listen for Test Event" button + a tool like
curl/httpie aimed at the test URL.
Step 3 — Classify the error
Pick the matching category from the table above and load that reference
doc. Most categories have a checklist.
Step 4 — Apply the fix
Common fix levers (least invasive first):
- Change node parameters — fix expressions, set headers, adjust
pagination.
- Add node-level resilience —
retryOnFail: true, maxTries: 3,
waitBetweenTries: 5000, continueOnFail: true,
onError: "continueErrorOutput".
- Add flow-level resilience — Wait node, Loop Over Items batching,
Stop and Error with a useful message.
- Change the workflow structure — add an error branch, extract a
sub-workflow, add an idempotency check.
- Add an Error Workflow at the instance level so future failures
notify someone.
Step 5 — Verify
- Manually re-execute with the failing input (use Pin Data or replay).
- Check the Executions tab to confirm the new run is green.
- For schedule/webhook workflows, monitor the next 1–3 production
executions before declaring victory.
Step 6 — Capture the lesson
If the root cause was non-obvious (most debugging is), append a dated entry
to LESSONS_LEARNED.md. Future-you will thank past-you.
Trigger never fires
If the workflow has no execution history and never fires:
- Manual Trigger — fires only when user clicks Execute Workflow. Won't
fire on a schedule.
- Workflow not activated — toggle is "Inactive" in the top bar. Webhook,
Schedule, App, and Form triggers only fire on production URLs when active.
- Webhook URL confusion — there are TWO URLs per Webhook node:
- Test URL (
/webhook-test/<path>) — works only when the editor is
open and the node has "Listen for Test Event" running.
- Production URL (
/webhook/<path>) — works whenever the workflow is
active.
- Schedule mode mismatch — "Interval" mode anchors to instance restart.
"Cron Expression" mode anchors to wall-clock. Switch to Cron Expression
for predictable schedules.
- Timezone mismatch — Schedule respects
settings.timezone on the
workflow, falling back to instance GENERIC_TIMEZONE. Verify both.
- Trigger node deleted from active workflow — n8n keeps the workflow
active and shows no error, but no triggers fire. Re-add the trigger and
toggle inactive → active to re-register.
- App trigger credential expired — Slack/Gmail/etc. OAuth tokens
expire. Re-authenticate.
- Queue mode worker not running — if the instance is in queue mode and
no worker is up, executions queue indefinitely. See
n8n-self-host.
See TRIGGER_PROBLEMS.md for deeper coverage.
Quick reference: node-level resilience flags
Set these on a node via the editor's "Settings" gear or in workflow JSON
under the node:
| Flag |
Effect |
retryOnFail: true |
Auto-retry on any thrown error |
maxTries: 3 |
Number of attempts (default 3) |
waitBetweenTries: 5000 |
Milliseconds between retries (default 1000) |
continueOnFail: true |
(legacy) On error, output a "fail item" to the regular output and continue |
onError: "continueRegularOutput" |
Modern: on error, output { error: {...} } to regular output |
onError: "continueErrorOutput" |
Modern: on error, output the error item to a SECOND output port (red dot in editor) |
onError: "stopWorkflow" |
Default: throw |
alwaysOutputData: true |
When input is empty OR node errors, still output one item (often {}) so downstream runs |
executeOnce: true |
Force node to run a single time even if multiple input items |
Don't blanket-apply continueOnFail — silent failures are worse than loud
ones. Use it deliberately where you have a recovery branch.
Best practices
Do:
- Pin data on the failing node BEFORE making fix attempts so you can
re-test deterministically.
- Add an Error Workflow at the instance level for any production workflow.
Pick one — Slack, PagerDuty, email — and wire it once.
- Use
onError: "continueErrorOutput" + a Set/Slack node on the error
branch to log structured failure data instead of silently dropping items.
- Add a unique correlation ID early in the workflow (Set node, UUID
expression) so you can grep logs/Slack alerts/database rows to one
execution.
- Set
EXECUTIONS_TIMEOUT (instance) and executionTimeout (workflow) to
realistic ceilings — runaway workflows are common.
- Use Workflow Insights (Enterprise) or query the
execution_entity
table directly for trend analysis.
Don't:
- Don't disable a failing node to "fix" it. Find the root cause; the
workflow only ran because the disabled node WAS doing work.
- Don't silently swallow errors with
continueOnFail and no downstream
handling. At minimum, log to an error branch.
- Don't keep increasing
maxTries on a node that's failing every time.
Retries are for transient errors; a persistent error needs a real fix.
- Don't debug by editing production. Duplicate the workflow ("Duplicate" in
the Workflows list), debug the copy, then port the fix back.
Continuous learning
After every non-trivial debugging session, append an entry to
LESSONS_LEARNED.md. The lesson is most valuable when
the error was misleading, the cause was non-obvious, or the fix surprised
you. Follow the Lesson entry template
in the agent file.
1---2name: n8n-debug-workflow3description: Diagnose and fix failing n8n workflow executions. Use when user says "my n8n workflow is failing", "execution errored", "this node returns an error", "rate limited", "Could not find paired item", "workflow is stuck", "webhook isn't firing", "Schedule trigger isn't running", "memory leak", "execution timeout", "data is empty in next node", "wrong data shape downstream", "items got duplicated", "binary data missing", or pastes an n8n execution error. Walks through reading the execution log, common-error catalog, item-linking forensics, rate-limit recovery, webhook/schedule debugging, and recovery patterns (retryOnFail, continueOnFail, Error Trigger). Do NOT use for designing new workflows (use n8n-build-workflow), writing Code nodes (use n8n-code-node), or hosting/Docker-level issues (use n8n-self-host).4license: MIT-05---67# n8n Debug Workflow89Diagnose failing n8n executions. Most n8n bugs fall into a handful of10categories — recognize the category, then apply the matching fix.1112**References:** [ERROR_CATALOG.md](references/ERROR_CATALOG.md) | [EXECUTION_DEBUGGING.md](references/EXECUTION_DEBUGGING.md) | [ITEM_LINKING_ERRORS.md](references/ITEM_LINKING_ERRORS.md) | [RATE_LIMITS.md](references/RATE_LIMITS.md) | [TRIGGER_PROBLEMS.md](references/TRIGGER_PROBLEMS.md)1314**Lessons:** [LESSONS_LEARNED.md](LESSONS_LEARNED.md) — read before non-trivial work.1516**Authoritative docs:** <https://docs.n8n.io/courses/level-two/chapter-4/> (debugging chapter) and <https://docs.n8n.io/flow-logic/error-handling/>.1718---1920## Triage in three questions2122Before opening logs, get the user to answer three questions. They short-circuit2380% of debugging:24251. **Which node fails?** Open the execution in the Editor → Executions tab.26 Look for the red node. Errors propagate upstream visually — the actual27 failure is the FIRST red node from the trigger.282. **What's the exact error message?** Copy it verbatim. n8n error messages29 are usually accurate; the model + free-text reasoning is almost always30 in the message.313. **Did this work before?** If yes — what changed? (Workflow edits, n8n32 version upgrade, credential rotation, API change upstream, schedule33 timezone shift.)3435If the user can't answer #1 because no execution log exists (workflow36never fires), jump to [Trigger never fires](#trigger-never-fires).3738---3940## Error categories (load the matching reference)4142| Symptom | Category | Reference |43|---|---|---|44| Node throws with API/transport error | API errors | [ERROR_CATALOG.md](references/ERROR_CATALOG.md#api--transport) |45| "Could not find paired item" / `$('X').item` throws | Item linking | [ITEM_LINKING_ERRORS.md](references/ITEM_LINKING_ERRORS.md) |46| HTTP 429, ETIMEDOUT, ECONNRESET storms | Rate limits | [RATE_LIMITS.md](references/RATE_LIMITS.md) |47| "Cannot read properties of undefined" in expression | Expression errors | [ERROR_CATALOG.md](references/ERROR_CATALOG.md#expression-errors) |48| Trigger doesn't fire / fires twice / fires late | Trigger problems | [TRIGGER_PROBLEMS.md](references/TRIGGER_PROBLEMS.md) |49| Execution stalls or times out | Execution problems | [EXECUTION_DEBUGGING.md](references/EXECUTION_DEBUGGING.md#stalled-executions) |50| Memory/disk usage spikes during execution | Execution problems | [EXECUTION_DEBUGGING.md](references/EXECUTION_DEBUGGING.md#resource-issues) |51| Webhook returns wrong status/body | Webhook problems | [TRIGGER_PROBLEMS.md](references/TRIGGER_PROBLEMS.md#webhook-response-issues) |52| Data is "missing" in a downstream node | Item linking OR run-mode | [ITEM_LINKING_ERRORS.md](references/ITEM_LINKING_ERRORS.md), then [EXECUTION_DEBUGGING.md](references/EXECUTION_DEBUGGING.md#run-modes) |5354---5556## Procedure (any debugging request)5758### Step 1 — Read the execution log5960In the Editor:61621. Open the workflow.632. Click the **Executions** tab.643. Open the failed execution.654. Click on the red (failed) node — the right panel shows input data,66 output data, and the error.675. Click upstream nodes to verify they actually produced the data the68 failed node expected.6970**Three things to extract:**7172- **Error message** (exact text, including the "On node X" prefix).73- **Input data to the failing node** — is it empty? Wrong shape?74- **Output data of the immediately-upstream node** — does it match what the75 failing node was expecting?7677### Step 2 — Reproduce locally if possible7879- Use **Pin Data** on the failing node: right-click → Pin (or set80 `pinData` in workflow JSON). This lets you re-run downstream without81 re-firing the trigger.82- Use the **Run from this Node** option (right-click on a node) to start83 execution from a specific node using its pinned data.84- For Webhook-triggered workflows, replay the original request using the85 Webhook node's **"Listen for Test Event"** button + a tool like86 `curl`/`httpie` aimed at the test URL.8788### Step 3 — Classify the error8990Pick the matching category from the table above and load that reference91doc. Most categories have a checklist.9293### Step 4 — Apply the fix9495Common fix levers (least invasive first):96971. **Change node parameters** — fix expressions, set headers, adjust98 pagination.992. **Add node-level resilience** — `retryOnFail: true`, `maxTries: 3`,100 `waitBetweenTries: 5000`, `continueOnFail: true`,101 `onError: "continueErrorOutput"`.1023. **Add flow-level resilience** — Wait node, Loop Over Items batching,103 Stop and Error with a useful message.1044. **Change the workflow structure** — add an error branch, extract a105 sub-workflow, add an idempotency check.1065. **Add an Error Workflow** at the instance level so future failures107 notify someone.108109### Step 5 — Verify110111- Manually re-execute with the failing input (use Pin Data or replay).112- Check the Executions tab to confirm the new run is green.113- For schedule/webhook workflows, monitor the next 1–3 production114 executions before declaring victory.115116### Step 6 — Capture the lesson117118If the root cause was non-obvious (most debugging is), append a dated entry119to [LESSONS_LEARNED.md](LESSONS_LEARNED.md). Future-you will thank past-you.120121---122123## Trigger never fires124125If the workflow has no execution history and never fires:126127- **Manual Trigger** — fires only when user clicks Execute Workflow. Won't128 fire on a schedule.129- **Workflow not activated** — toggle is "Inactive" in the top bar. Webhook,130 Schedule, App, and Form triggers only fire on production URLs when active.131- **Webhook URL confusion** — there are TWO URLs per Webhook node:132 - **Test URL** (`/webhook-test/<path>`) — works only when the editor is133 open and the node has "Listen for Test Event" running.134 - **Production URL** (`/webhook/<path>`) — works whenever the workflow is135 active.136- **Schedule mode mismatch** — "Interval" mode anchors to instance restart.137 "Cron Expression" mode anchors to wall-clock. Switch to Cron Expression138 for predictable schedules.139- **Timezone mismatch** — Schedule respects `settings.timezone` on the140 workflow, falling back to instance `GENERIC_TIMEZONE`. Verify both.141- **Trigger node deleted from active workflow** — n8n keeps the workflow142 active and shows no error, but no triggers fire. Re-add the trigger and143 toggle inactive → active to re-register.144- **App trigger credential expired** — Slack/Gmail/etc. OAuth tokens145 expire. Re-authenticate.146- **Queue mode worker not running** — if the instance is in queue mode and147 no worker is up, executions queue indefinitely. See148 [n8n-self-host](../n8n-self-host/SKILL.md).149150See [TRIGGER_PROBLEMS.md](references/TRIGGER_PROBLEMS.md) for deeper coverage.151152---153154## Quick reference: node-level resilience flags155156Set these on a node via the editor's "Settings" gear or in workflow JSON157under the node:158159| Flag | Effect |160|---|---|161| `retryOnFail: true` | Auto-retry on any thrown error |162| `maxTries: 3` | Number of attempts (default 3) |163| `waitBetweenTries: 5000` | Milliseconds between retries (default 1000) |164| `continueOnFail: true` | (legacy) On error, output a "fail item" to the regular output and continue |165| `onError: "continueRegularOutput"` | Modern: on error, output `{ error: {...} }` to regular output |166| `onError: "continueErrorOutput"` | Modern: on error, output the error item to a SECOND output port (red dot in editor) |167| `onError: "stopWorkflow"` | Default: throw |168| `alwaysOutputData: true` | When input is empty OR node errors, still output one item (often `{}`) so downstream runs |169| `executeOnce: true` | Force node to run a single time even if multiple input items |170171Don't blanket-apply `continueOnFail` — silent failures are worse than loud172ones. Use it deliberately where you have a recovery branch.173174---175176## Best practices177178**Do:**179- Pin data on the failing node BEFORE making fix attempts so you can180 re-test deterministically.181- Add an Error Workflow at the instance level for any production workflow.182 Pick one — Slack, PagerDuty, email — and wire it once.183- Use `onError: "continueErrorOutput"` + a Set/Slack node on the error184 branch to log structured failure data instead of silently dropping items.185- Add a unique correlation ID early in the workflow (Set node, UUID186 expression) so you can grep logs/Slack alerts/database rows to one187 execution.188- Set `EXECUTIONS_TIMEOUT` (instance) and `executionTimeout` (workflow) to189 realistic ceilings — runaway workflows are common.190- Use **Workflow Insights** (Enterprise) or query the `execution_entity`191 table directly for trend analysis.192193**Don't:**194- Don't disable a failing node to "fix" it. Find the root cause; the195 workflow only ran because the disabled node WAS doing work.196- Don't silently swallow errors with `continueOnFail` and no downstream197 handling. At minimum, log to an error branch.198- Don't keep increasing `maxTries` on a node that's failing every time.199 Retries are for transient errors; a persistent error needs a real fix.200- Don't debug by editing production. Duplicate the workflow ("Duplicate" in201 the Workflows list), debug the copy, then port the fix back.202203---204205## Continuous learning206207After every non-trivial debugging session, append an entry to208[LESSONS_LEARNED.md](LESSONS_LEARNED.md). The lesson is most valuable when209the error was misleading, the cause was non-obvious, or the fix surprised210you. Follow the [Lesson entry template](../../agents/n8n.agent.md#lesson-entry-template)211in the agent file.