A confident, specific, wrong suggestion
The validator didn't hedge. Its output included a full before/after code comparison, labeled INCORRECT and CORRECT, plus the exact operation needed to fix it: move the "Telegram - Render Failed" and "Reset Topic On Failure" nodes from the IF node's first output array to its second, and add an onError property. That's a level of specificity that invites trust — it reads like a tool that has actually inspected the logic and knows what's wrong, not a generic linter warning.
What the validator is actually pattern-matching on
The heuristic behind this message treats a node's two outputs as if they always mean "success" and "error" — a convention that's real and correct for a node's own onError: continueErrorOutput output, where output 0 genuinely is the success path and output 1 genuinely is the error path. A plain IF node's two outputs don't mean that at all; they mean "condition true" and "condition false," and which one represents success or failure depends entirely on what the condition checks and how the workflow's author decided to route each branch. The validator appears to guess at this by scanning the names of the nodes connected to each branch — seeing "Failed" and "Reset ... Failure" downstream of output 0 was apparently enough to conclude output 0 must be a wrongly-placed error path.
Why the guess was backwards here
The actual condition is attempt >= 4. TRUE means the retry budget is exhausted — that is the failure case, and routing it to a Telegram alert plus a Sheets reset is exactly correct, not a mistake to be swapped. FALSE means there's still budget left, and that path correctly goes to "Increment Attempt" to try again. The validator's proposed fix would have swapped these: the failure-notification path would fire on output 1 (FALSE, meaning every single under-the-limit retry) instead of output 0 (TRUE, meaning genuinely out of retries), while the real exhausted-retries case would fall through to output 0 with nothing wired to it at all. The workflow would have gone from "alert only after 4 real failures" to "alert on every retry, and never actually alert when retries run out" — worse in both directions at once.
How this almost went unnoticed
The fix was applied once, exactly as suggested, and the workflow still validated cleanly afterward — a swapped IF branch is structurally valid, it's just semantically backwards, and structural validation has no way to know that. The only thing that caught it was going back to read the IF node's actual condition before trusting the change, rather than trusting the validator's own before/after framing of what "correct" meant. Re-reading it took under a minute; not doing so would have shipped a workflow that pages someone on every normal retry and stays silent the one time it's actually supposed to.
The generalizable rule
A validator's "incorrect error output configuration" message on a plain IF node is worth treating as a hypothesis, not a verdict — especially when it's inferring intent from node names rather than from the condition's actual logic. Before applying a suggested branch swap on any IF node, read what the condition checks and confirm, independently, which branch is actually supposed to represent the failure case. If the current wiring already matches that, the validator's pattern-matched guess is a false positive, and the real fix is to leave it alone.
IF outputs versus error outputs
| IF node outputs | Error output (On Error: Continue using error output) | |
|---|---|---|
| Output 0 | Condition is true | Success: items the node processed normally |
| Output 1 | Condition is false | Error: items that failed |
| Meaning decided by | The condition you wrote | n8n |
A validator that applies the right-hand column to an IF node will be wrong whenever the condition describes a failure, such as "attempts exceeded" or "status is error". In those workflows, true is the failure branch, and that is correct.
Naming conditions so the next reader can't misread them
Most of the confusion here came from a condition whose true branch is the bad case. Some ways to make that obvious to people and tools alike:
- Name the IF node after the question it answers, with the answer that leads to the failure path: "IF - Attempts Exceeded" is better than "IF - Check Attempts".
- Where it reads naturally, flip the condition so true means "continue":
attempt < 4on the retry branch and the give-up path on false. Then even a name-based heuristic gets it right. - Put a sticky note next to loops and give-up branches that says in one line what each output does.
Testing that the branches really do what the names say
Structure validation can't tell a correct branch from a swapped one. A test can. For this loop the quickest one is to run the workflow once with the attempt limit set to 1: the very first failed poll must go down the give-up path, send the alert and reset the topic. If it loops instead, the branches are swapped. Afterwards set the limit back, and confirm that by reading the node back, not from memory.
The general rule I follow now: a validator's suggestion that changes behaviour, rather than syntax, gets applied only after I can say in one sentence why the current behaviour is wrong.
Frequently asked questions
Is n8n's 'incorrect error output configuration' warning always right?
No. On a plain IF node the two outputs mean true and false, not success and error. If the condition describes a failure, the true branch is correctly the failure path.
How do the outputs of an IF node differ from an error output?
An IF node's outputs depend on the condition you wrote. An error output, enabled with On Error: Continue (using error output), always sends failed items to the second output.
How do I test which branch a retry loop takes?
Temporarily set the attempt limit to 1 and run the workflow. The first failure must take the give-up path. Restore the limit afterwards and read the node back to confirm.
Does a workflow that validates cleanly behave correctly?
Not necessarily. Validation checks structure. Swapped branches are structurally valid and only show up in a test run.
n8n Automation Hub