Production workflows must handle failures gracefully. This lesson covers node-level error options, global error workflows, alerting, and safe testing practices.
Every node in n8n has an "On Error" setting accessible from the node's settings panel (gear icon or the Settings tab).
| Mode | Behaviour | Best for |
|---|---|---|
| Stop Workflow | Halts execution immediately on error | Critical steps where failure must stop all processing |
| Continue | Error is ignored, workflow continues with next item | Best-effort steps, optional enrichments |
| Continue With Error Output | Error data passed to next node instead of normal output | When you want to log or alert on each individual failure |
Create a separate workflow with an Error Trigger node as the first node. In any other workflow's Settings, set "Error Workflow" to this catcher workflow. It fires automatically when that workflow fails.
# Error Trigger data available in the catcher workflow: $json.execution.id # Failed execution ID $json.execution.url # Link to the failed execution $json.workflow.id # Workflow that failed $json.workflow.name # Workflow name $json.error.message # Error message $json.error.stack # Stack trace $json.lastNodeExecuted # Node name where it failed
# Catcher workflow structure:
Error Trigger
└─► Set Node (format alert message)
└─► Slack / Telegram / Email (send alert)
Use "Continue With Error Output" + an IF node to build a try/catch style pattern inline:
# Step 1: HTTP Request node
On Error: Continue With Error Output
# Step 2: IF node after HTTP Request
Condition: {{ $json.error }} exists
TRUE branch → handle error (log, alert, fallback)
FALSE branch → continue with successful response
# The error output item has this shape:
{
"error": "Request failed with status 404",
"statusCode": 404,
"node": "Fetch User"
}
# Execution statuses: success → all nodes completed without error error → at least one node threw an unhandled error running → currently executing waiting → paused at a Wait node canceled → manually stopped
# In the Error Catcher workflow:
Error Trigger
└─► Slack node (Send Message)
Channel: #alerts
Message:
*Workflow Failed* :red_circle:
Workflow: {{ $json.workflow.name }}
Error: {{ $json.error.message }}
Node: {{ $json.lastNodeExecuted }}
View: {{ $json.execution.url }}
# Telegram node
Chat ID: your-chat-id
Message:
❌ n8n Error
Workflow: {{ $json.workflow.name }}
Error: {{ $json.error.message }}
Time: {{ $now.toFormat('yyyy-MM-dd HH:mm') }}
# Environment variables to control log retention: EXECUTIONS_DATA_MAX_AGE=30 # Delete logs older than 30 days EXECUTIONS_DATA_SAVE_ON_ERROR=all # Save logs: all/none EXECUTIONS_DATA_SAVE_ON_SUCCESS=none # Don't save successful runs EXECUTIONS_DATA_SAVE_ON_PROGRESS=false # Why limit logs? # - Execution data can grow large, especially with binary files # - Postgres performance degrades with millions of rows # - Set to save errors only in high-volume automations
The Wait node pauses a workflow execution for a specified time or until a webhook resumes it.
# Time-based wait:
Resume: After Time Interval
Wait Amount: 30
Wait Unit: Minutes
# Execution is paused — does not consume resources
# Webhook-based resume:
Resume: On Webhook Call
# n8n gives you a unique "resume URL"
# Send a POST to that URL to continue the workflow
# Use case: send approval email, wait for user to click "Approve"
Webhook Trigger
└─► Send Email with approval link (contains resume URL)
└─► Wait (Resume: Webhook)
└─► IF approved → process / reject → log