n8n Error Trigger vs heartbeat monitoring
Which n8n failures the Error Trigger catches, which only a heartbeat catches, and how to wire both together.
If you run n8n in production, you've probably set up an error workflow: a workflow starting with the Error Trigger node that posts to Slack whenever something fails. That's a good first step. It still leaves one class of failure uncovered. The Error Trigger reacts to a failed execution. A heartbeat reacts to a missing successful one. This page compares the two and shows how to run them together.
How the Error Trigger works
From the n8n docs:
- Create a workflow that starts with the Error Trigger node, for example
Error Handler, and save it. - In each workflow you want covered, open Options → Settings, pick it under Error workflow, and save.
- When an automatic execution of that workflow fails, the error workflow runs with details about the failure.
A few documented details are easy to miss:
- One error workflow can serve many workflows.
- A workflow containing an Error Trigger uses itself as its error workflow by default, and it doesn't have to be published to work.
- You can't test it with a manual run. The Error Trigger only fires when an automatic execution errors, e.g. from a schedule or webhook.
- The data includes
execution.error.message,execution.lastNodeExecuted,execution.urlandworkflow.name. If the error came from the trigger node of the main workflow, the shape changes: there's no execution ID or URL, and the details are in atriggerobject instead. - The Stop And Error node lets you fail an execution on purpose. That's how you turn "this result is wrong" into something the error workflow sees.
How a heartbeat works
The workflow calls a unique URL at the end of every successful run. A monitoring service knows the expected interval. If no ping arrives within interval + grace period, it alerts. It doesn't need to know why the run didn't succeed, so it catches failures that never produce an error.
What each one catches
| Scenario | Error Trigger | Heartbeat |
|---|---|---|
| A node throws an error and the execution fails | Yes, immediately | Yes: after the deadline, or immediately with a /fail ping |
| A node is set to On Error: Continue and errors | No, the execution succeeds | Yes, with output checks on the final data |
An API returns 200 with an empty list, and the workflow "succeeds" with nothing | No | Yes, with output checks |
| The workflow is unpublished or deactivated | No | Yes |
| The schedule is changed by mistake, or the webhook sender stops calling | No | Yes |
| The n8n instance or its worker is down | No: nothing runs, including the error workflow | Yes, the monitor is external |
| An execution hangs, waiting or running forever | No | Yes, with a /start ping |
| The error workflow itself fails, e.g. an expired Slack credential | No alert at all | Unaffected |
| Rich context: failing node, message, execution link | Yes | Only what you send in the ping body |
The pattern: the Error Trigger is better at explaining failures, and a heartbeat is better at noticing them. The first needs n8n to be running and to recognize the failure. The second assumes neither.
Using both: the recommended setup
1. Add a success ping to each important workflow
Create a monitor in Flowhush (New monitor, with Expected every (seconds) matching the schedule) and add an HTTP Request node as the workflow's last step:
Method: GET
URL: https://flowhush.com/p/YOUR-MONITOR-UUID
Settings → Execute Once: on
Settings → Retry On Fail: on
Settings → On Error: Continue
On Error: Continue on the ping node means a network blip never fails your real workflow. If you're on Pro, switch to POST, turn on Send Body with Body Content Type JSON and Specify Body Using JSON, set the body to {{ JSON.stringify($json) }}, and add Required JSON keys on the monitor so empty results count as failures.
2. Make the error workflow report to the right monitor
Keep your existing Slack or email notification in the error workflow, and also send a /fail ping so the monitor goes down immediately instead of waiting for the deadline. Add a Code node after the Error Trigger that maps workflow IDs to ping URLs. IDs are safer than names, which people rename.
// Code node (Run Once for All Items) in the error workflow
const urls = {
'aB3dE5fG7hJ9kL1m': 'https://flowhush.com/p/YOUR-MONITOR-UUID', // Daily invoice sync
'nP2qR4sT6uV8wX0y': 'https://flowhush.com/p/OTHER-MONITOR-UUID', // Lead enrichment
};
const d = $input.first().json;
const message = d.execution?.error?.message ?? d.trigger?.error?.message ?? 'unknown error';
return [{
json: {
url: urls[d.workflow?.id] ?? '',
workflow: d.workflow?.name ?? '',
node: d.execution?.lastNodeExecuted ?? 'trigger',
error: message,
},
}];
The workflow ID is the part of the editor URL after /workflow/. Then add an IF node ({{ $json.url }} is not empty) and an HTTP Request node:
Method: POST
URL: {{ $json.url }}/fail
Send Body: on
Body Content Type: JSON
Specify Body: Using JSON
JSON: {{ JSON.stringify({ workflow: $json.workflow, node: $json.node, error: $json.error }) }}
Settings → On Error: Continue
Flowhush marks the monitor down with "Run reported failure via /fail", sends one alert, and stores the first 1 KB of the body in Recent pings. The next successful run sends a recovery alert, which the Error Trigger can't do because it only knows about failures.
3. Turn soft failures into real ones
Where a workflow can "succeed" with bad data, add an IF check and a Stop And Error node on the bad branch, e.g. "no rows returned on a weekday". The execution then fails, the error workflow runs, and the heartbeat ping at the end is skipped. Both signals agree.
Testing the setup
Because manual runs don't fire the Error Trigger, test it with a production execution: temporarily point a scheduled workflow at a URL that fails, or add a Stop And Error node, then wait for the next scheduled run. Test the heartbeat side from a terminal:
curl -fsS https://flowhush.com/p/YOUR-MONITOR-UUID # success → OK
curl -fsS -X POST -H 'Content-Type: application/json' \
-d '{"error":"manual test"}' https://flowhush.com/p/YOUR-MONITOR-UUID/fail
Use Send test alert on the monitor page to check that your Slack, Discord, Telegram or email channel receives alerts without changing the monitor's status. A monitor stays in the new state and sends no alerts until its first ping. That way a workflow you haven't deployed yet doesn't page you.
Which should you use?
- Only a few low-stakes workflows: the Error Trigger alone is reasonable. You'll miss silent stops, but you'll see crashes.
- Workflows whose absence costs money (billing syncs, lead routing, backups, reports someone relies on): add a heartbeat. The Error Trigger can't tell you a workflow didn't run.
- Self-hosted n8n: add a heartbeat, because your instance going down is a real failure mode and an error workflow can't report it.
Flowhush's Free plan covers 5 workflows with email, Slack, Discord or Telegram alerts. That's enough to put a heartbeat on the workflows you'd least like to fail silently.
Monitor your first workflows free
The Free plan includes 5 heartbeat monitors with alerts to email, Slack, Discord or Telegram. No credit card required.
Start free — 5 monitors See setup snippetsSources
- n8n docs: Error Trigger node
- n8n docs: Handle errors gracefully (error workflows, Stop And Error)
- n8n docs: Node settings
- n8n docs: HTTP Request node
Third-party features and prices were checked on 3 November 2026 and may have changed since.