I build reporting automations for agencies and freelancers. What finally pushed me to productize one wasn’t the report itself — it was noticing how many production workflows die silently.
**What it does**
- Pulls metrics (Google Sheet as default source, swappable for APIs)
- Renders a branded HTML report per client
- Emails each client on their own schedule
**The design decision I want feedback on**
Instead of relying only on a global Error Workflow, I ship a second monitoring workflow alongside the main one:
1. The main workflow logs every run (success/fail + row counts) to a small log sheet
2. The monitor checks that log on a schedule and emails ME if a run is missing, failed, or produced zero rows
3. The case that bit me: “zero rows but technically successful” — the report sends, but it’s empty. Continue-on-fail hides exactly this class of problem, so the monitor validates output shape, not just execution status
My thinking: an Error Workflow catches crashes, but it can’t catch “ran fine, sent garbage.” A separate watcher validating output feels more robust for client-facing automations.
How do others here handle that failure class — inline output-validation nodes? Retry patterns? Genuinely curious what patterns hold up at scale.
(I packaged the full version with docs as a paid template — fine to DM me about it, not dropping a link here. A free lite version for the community is in the works.)
2 Likes
Welcome to the community, @Muddassir_Ahmed! The external monitoring workflow design is the right call - the inline check lives inside the workflow it’s supposed to catch, so anything that stops the main workflow early also stops the check. Your log sheet + separate watcher survives that whole class of failure. One small improvement to consider: add a last_heartbeat timestamp column alongside each run entry and have the monitor alert if a workflow hasn’t written a heartbeat within 2x its expected schedule interval. That catches the case where the workflow was deactivated accidentally or the n8n instance restarted and the schedule trigger never re-registered - none of which produce log entries at all.
1 Like
Thanks @nguyenthieutoan — the heartbeat column closes the exact gap I hadn’t: my log-based watcher only fires on rows that exist, so a silently-deactivated workflow, or a restart where the schedule trigger never re-registers, writes nothing and there’s nothing to catch. last_heartbeat + ‘alert if nothing within 2× the expected interval’ turns absence-of-signal into a signal, which output-validation can’t do.
One thing I’m still chewing on: whatever writes the heartbeat has to survive the same failure it’s meant to detect. Right now my monitor is a second n8n workflow, but a full-instance restart would take both down together — so I’ve been leaning toward moving the watcher fully out-of-band (an external cron/uptime check reading the log) so the thing doing the worrying can’t die the same way the thing it’s watching does. Do you keep your monitor in-instance or outside it? Appreciate you pressure-testing this.
1 Like
Small update for anyone finding this thread: I pulled the basic error-alert layer out into a standalone n8n workflow and put it up free. Import it, point it at email or Slack, and it pings you the second a workflow crashes. It’s the “obvious failures” half of what we were discussing here — the silent green-but-empty case is the harder problem I’m still building. Free if it’s useful: Silent-Failure Starter Kit for n8n