The 9 ways n8n workflows die silently (checklist from 3 production scars

After an error workflow that turned out not to be attached to anything, a Schedule Trigger that silently dropped one of its cron expressions, and a webhook that walked straight past my form validation — I wrote down every way I’ve seen n8n workflows stop without any error appearing anywhere, and the 60-second check for each.

A thrown error is the good outcome: something noticed. Every item below is a way a workflow stops doing its job with no error in any log.

1. No error workflow is attached — per workflow.
n8n does not inherit a global error handler. A new workflow ships with no error workflow, so its failures alert no one.
:white_check_mark: Check: open every workflow → Settings → Error Workflow. If it’s empty, its errors are invisible.

2. The workflow toggle is off.
Someone deactivated it (or an import/restore left it inactive) and every schedule and webhook simply stopped.
:white_check_mark: Check: Workflows list → filter by Inactive → is anything there that shouldn’t be?

3. Manual tests lie to you.
“Test workflow” runs work even when the workflow is inactive, and error workflows do not fire on manual runs. Everything looks fine on your screen while production is dead.
:white_check_mark: Check: after any change, confirm one production run in the executions list — don’t sign off on a manual test.

4. Multiple cron expressions in one Schedule Trigger.
On some versions, a Schedule Trigger holding several cron expressions silently drops some of them. The workflow “works” — on a fraction of its schedule.
:white_check_mark: Check: one cron expression per trigger.

5. No timezone set.
Schedules default to the server’s timezone (often UTC). Your “9am daily” runs at 5pm.
:white_check_mark: Check: every scheduled workflow → Settings → timezone explicitly set.

6. Alternate entry points skip your validation.
A Form Trigger’s required fields protect the form — not the webhook URL that enters the same flow. A direct POST with garbage sails through.
:white_check_mark: Check: every entry point gets its own validation guard before anything irreversible.

7. The instance itself died.
Container OOM-killed, VPS rebooted, plan suspended — no n8n, no error trigger, no alert. This class cannot be caught from inside at the moment it happens; you catch it because expected runs stop appearing.
:white_check_mark: Check: a heartbeat/dead-man’s-switch workflow that reads your execution list on a schedule and alerts when a watched workflow hasn’t run. (Plus one free external uptime ping if you’re paranoid.)

8. Credentials expired.
OAuth revoked, API keys rotated. Depending on the node this fails loudly — or returns empty results forever.
:white_check_mark: Check: a daily digest makes “erroring for 4 days” impossible to miss; for quiet-empty failures, add a sanity node (“0 rows? alert.”) where empty is abnormal.

9. Data changed shape upstream.
A renamed column, a null where a string lived. Code nodes produce empty output — which flows onward as “success.”
:white_check_mark: Check: anywhere you’d rather crash than continue wrong: if (!items.length) throw new Error('Expected data, got none');

The principle behind all nine: silence is not health. A healthy system tells you it’s alive; only broken systems are quiet. That’s why my third layer is a digest that arrives every morning — the day it doesn’t arrive is itself the alert.

Happy to answer questions about any of these.

I also packaged the three workflows I run against these (global error alert, heartbeat/dead-man’s switch, daily digest) as a small paid kit for anyone who’d rather import than assemble: The n8n Reliability Kit — error alerts, dead-man's switch & daily health digest — the checklist above is the whole diagnostic though; you can build every fix yourself from it.

إعجاب واحد (1)