Most n8n tutorials show the happy path. But real workflows fail — APIs go down, webhooks return unexpected data, rate limits kick in. If you haven't wired up error handling, your workflow silently dies and you have no idea what broke.
This guide covers every error handling tool n8n gives you, when to use each one, and includes a free workflow JSON you can import and adapt.
The 3 layers of n8n error handling
- Node-level — Stop On Error / Continue On Error settings per node
- Workflow-level — Error Workflow (a separate workflow that fires when yours fails)
- Branch-level — IF node or Switch node to route errors explicitly
Most people only use layer 1. All three together make your workflows truly resilient.
Layer 1: Node settings — Continue On Error
Every n8n node has an On Error setting (in the node's Settings tab):
- Stop Workflow (default) — any error halts the entire run
- Continue (using error output) — the node outputs the error as data and execution continues
- Continue (ignoring error) — silently skip items that error, continue with the rest
When to use Continue (using error output):
When you want to handle the error downstream — route failed items to a Slack alert, a Google Sheet log, or a retry queue.
When to use Continue (ignoring error):
For non-critical steps where partial success is fine. Example: enriching contact data from a third-party API — if one lookup fails, skip it and continue processing the rest.
Layer 2: Error Workflow
The Error Workflow is a separate n8n workflow that fires automatically whenever any workflow in your instance fails with an unhandled error.
How to set it up:
- Create a new workflow — add an Error Trigger node as the starting node
- Wire it to your alert action (Slack message, email, Google Sheet entry)
- Go to Settings → n8n Settings → set "Error Workflow" to your new workflow
The Error Trigger node gives you:
-
{{ $json.workflow.name }}— which workflow failed -
{{ $json.execution.id }}— link to the failed execution -
{{ $json.error.message }}— the error message -
{{ $json.error.node.name }}— which node failed
Example Slack alert:
Workflow failed: {{ $json.workflow.name }}
Node: {{ $json.error.node.name }}
Error: {{ $json.error.message }}
Execution: https://your-n8n-instance/executions/{{ $json.execution.id }}
This is the single highest-leverage error handling step you can take. One Error Workflow covers every workflow in your instance.
Layer 3: Branch-level error routing with IF node
Sometimes you want finer control — handle specific error types differently, or retry before alerting.
Pattern: Retry once, then alert
- HTTP Request node → Continue (using error output)
- IF node:
{{ $json.error }}exists → true branch = retry path, false branch = success path - On the retry path: Wait node (30s delay) → same HTTP Request again
- Second failure → Slack alert
Pattern: Route by HTTP status code
IF: {{ $json.statusCode }} === 429
→ Wait 60s → retry
IF: {{ $json.statusCode }} === 401
→ Alert "credentials expired"
IF: {{ $json.statusCode }} >= 500
→ Alert "upstream API down"
Common mistake: not logging enough context
When an error alert fires at 3am, you need enough context to diagnose without replaying the execution. Always log:
- The input data that caused the error (first 500 chars)
- The node name
- The full error message
- A direct link to the execution
- Timestamp
Use a Set node before your alert node to assemble these into a clean object.
Free workflow JSON: Error handling starter
This workflow demonstrates all three layers:
- An HTTP Request with Continue On Error enabled
- An IF node routing errors vs. successes
- A mock Slack alert for the error path
- Comments explaining each choice
Import it: n8n menu → Import from JSON → paste below
{
"name": "Error Handling Starter",
"nodes": [
{
"parameters": {},
"id": "trigger-1",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"url": "https://httpstat.us/500",
"options": {}
},
"id": "http-1",
"name": "HTTP Request (may fail)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [460, 300],
"onError": "continueErrorOutput"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true },
"conditions": [
{
"leftValue": "={{ $json.error }}",
"rightValue": "",
"operator": { "type": "string", "operation": "exists" }
}
]
}
},
"id": "if-1",
"name": "Error occurred?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [680, 300]
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "1", "name": "alert_message", "value": "={{ 'FAILED: ' + $json.error.message }}", "type": "string" },
{ "id": "2", "name": "failed_node", "value": "={{ $json.error.node?.name || 'unknown' }}", "type": "string" }
]
}
},
"id": "set-1",
"name": "Build alert",
"type": "n8n-nodes-base.set",
"typeVersion": 3,
"position": [900, 200]
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "3", "name": "status", "value": "success", "type": "string" }
]
}
},
"id": "set-2",
"name": "Success path",
"type": "n8n-nodes-base.set",
"typeVersion": 3,
"position": [900, 400]
}
],
"connections": {
"Manual Trigger": { "main": [[{ "node": "HTTP Request (may fail)", "type": "main", "index": 0 }]] },
"HTTP Request (may fail)": {
"main": [[{ "node": "Error occurred?", "type": "main", "index": 0 }]],
"error": [[{ "node": "Error occurred?", "type": "main", "index": 0 }]]
},
"Error occurred?": {
"main": [
[{ "node": "Build alert", "type": "main", "index": 0 }],
[{ "node": "Success path", "type": "main", "index": 0 }]
]
}
},
"pinData": {},
"settings": { "executionOrder": "v1" }
}
Quick reference: which pattern to use
| Situation | Pattern |
|---|---|
| Simple "alert me if anything breaks" | Error Workflow (layer 2) |
| Skip bad items, process the rest | Continue (ignoring error) |
| Retry once before alerting | Continue (error output) + IF + Wait + retry |
| Route by HTTP status code | Continue (error output) + Switch node |
| Log all failures to a sheet | Continue (error output) + Google Sheets append |
If you want more pre-built n8n workflows like this — covering webhooks, Stripe payments, Gmail automation, and more — I put together a Workflow Starter Pack with 10 ready-to-import JSONs ($29, one-time).
Drop any error handling questions in the comments — happy to help debug.
Top comments (1)
What's your go-to error handling pattern in n8n?
For me it's always: set the Error Workflow first (catches everything globally), then add Continue On Error to any node that hits an external API. The IF-node retry pattern for 429 rate limits has saved me more times than I can count.
Drop your setup in the comments - curious what people are doing for production workflows.