Ran Fine

Four ways an n8n workflow reports success and does nothing

Every one of these completes. Every one returns status: success. None of them fire an error workflow, and none of them appear in any log as a failure. Reproductions included, measured on self-hosted 2.36.7.

An error workflow catches errors. That is the easy half, and it is the half everybody has. The failures that cost you a client are the ones where nothing throws: the run finishes, every node is green, and no records moved.

What follows is four of them, with what n8n actually records in each case. The last one contradicts the obvious way to detect it, which is why it is worth writing down.

The four

01

A branch whose condition no longer matches

status: success

An upstream field gets renamed, or a value drifts out of range, and an IF condition that used to match stops matching. The nodes on that branch never run.

The obvious detection does not work. You would expect the skipped node to appear in runData with a non-success executionStatus. It does not appear at all. Checking node statuses for something that failed returns only healthy nodes.

Every minute    executionStatus=success   branches=[1]
Emit 5 rows     executionStatus=success   branches=[5]
Condition       executionStatus=success   branches=[0, 5]

declared but ABSENT from runData: ['Send invoice']

The signal is a missing key, not a bad value. To catch it you have to know which nodes normally run and notice one stopped — absence alone is not a fault, because the untaken side of an IF is absent on every healthy run too.

Reproduce it: Schedule Trigger → Code node emitting a few rows → IF that can never match → Code node on the true branch. Read data.resultData.runData from the execution. The true-branch node simply is not there.

02

A credential that expires before the request leaves

no HTTP status at all

An OAuth token expires. n8n fails at the signing step, before any request goes out, with something like Unable to sign without access token.

There is no status code to catch. Error handling built around HTTP responses — retry on 5xx, alert on 4xx — never sees this, because no HTTP exchange happened.

03

A disabled node passing input straight through

status: success

Someone disables a node to test something and does not re-enable it. On a production run a disabled node passes its input to the next node untouched.

The enrichment, validation or transformation that node was doing silently stops happening. The row count is unchanged, so anything checking volume sees nothing wrong. The data is simply less correct than it was.

04

A run that produces 60% of normal

success · non-zero rows

Zero rows is the easy case and almost everyone checks for it. The expensive case is the run that quietly returns most of what it should, because it passes every emptiness assertion ever written, including a fixed floor.

A fixed threshold cannot catch this and a flat average makes it worse. Compare each run against a median of comparable runs instead — and give the baseline a calendar, because a client whose Monday is legitimately ten times its Tuesday will either alert every Monday or hide a collapsed one behind the week's average.

What they have in common

None of them are errors. Every one completes, reports success, and leaves a log that reads as healthy. They differ in mechanism and share a shape: you asked the system whether it was working, and it answered from inside itself.

Anything running inside n8n inherits n8n's blind spots. A check that only fires on errors cannot see a non-error. A watcher that is itself a workflow cannot report that the instance is down. That is why the detection above reads execution history from outside the instance, through the public API, with no nodes added to any workflow.

I do fixed-fee reliability audits for n8n and Make automations — one week, a written report naming which of your workflows fail silently today and what breaks first.

There is a full sample, run against my own production stack and published unedited, including the five silent failures it found there.

Read the sample audit

Scope

Case 1 was measured on self-hosted 2.36.7 via the public API and reproduced end to end. I have not checked whether older versions record the absent node differently. Cases 2 and 3 are described from behaviour reported by other operators and consistent with what I have seen; case 4 is an argument about detection rather than a claim about n8n internals. The monitoring described is open source: github.com/moneywithjjcom-del/ranfine-