I audited my own automations and found the auditor was broken
There's a bug class in n8n that silently breaks AI workflows. I wrote a checker for it, ran it across 98 workflows, and got 121 findings. About half were my checker's fault. The rest were worse than I thought.
There is a failure mode in n8n that produces no error, no warning, and no clue in the execution log. Certain nodes — httpRequest, emailSend, a Postgres write — replace the item flowing through the workflow with their own response. Anything downstream that reads the original data gets undefined instead. The workflow completes. It reports success. It just quietly did the wrong thing.
For an automation that answers your customers, that is the worst possible shape of bug: an agent that appears healthy while sending an email with a blank name in it, or routing a lead down the wrong branch because the field it checked was never there.
So I wrote a static checker. It walks each workflow's node graph, works out which nodes actually run before which, and flags every place a node reads a field off an item its parent has already replaced. Then I ran it across all 98 workflows in our catalogue.
It came back with 121 findings across nine builds.
Then I did the thing that turned out to matter more than the audit: before fixing anything, I checked whether the failures were real. Five separate times, over five days, the answer was no.
It was reading sticky notes — the yellow comment boxes you pin to an n8n canvas — as if they were executable code, so documentation was being reported as broken references. It didn't recognise executeWorkflowTrigger as a trigger, so working sub-workflows were flagged as having no entry point at all. It called a defensive fallback a bug: code that tries the current Anthropic response field and falls back to the legacy one is careful, not broken. It flagged a Google Business API's own response fields as missing data, because the node had written “const resp = $json” first — the parent replacing $json is the entire point of that line, and my checker treated it as the failure. And it flagged a node for downloading a file from the URL that the previous node had just fetched in order to get the URL.
Thirty findings, spread across three products, every single one of them wrong. One of those three is the engine that drafts replies to customer reviews — I had it listed as not ready to sell for four days because of a bug in my own test. Another had twenty-one findings and no defects at all.
The fix wasn't another exception. Adding field names to an allow-list one at a time was losing the argument: the next build would read a different field and I'd be back. The checker now recognises the pattern instead — a variable assigned bare $json, named the way people name responses, is holding an API's output, and its fields are not checked against what came before.
The worst finding of the week wasn't a false positive at all, though. One build keeps its workflow files at the top of its folder instead of in the n8n subfolder every other build uses. My sweep looked in the subfolder, found nothing, and printed ALL CLEAN. It had been sitting in the green column for four days on the strength of auditing an empty directory — and I had quoted that green in a status report.
It now exits with an error if it audits zero files. A test that cannot fail is worse than having no test, because you believe it.
There's a second-order version of the same mistake in here, and it's the one I'd want a client to hold me to: I wrote down that one of these had been fixed two days before it actually was. The diagnosis was right, the patch never landed, and nothing re-checked the claim. Being wrong is survivable. Recording that you've corrected it when you haven't is how a red row quietly becomes a green one.
Then the corrected checker found something the old one structurally could not: it had only ever looked one step back. A replaced item survives an IF or a Switch untouched, and in the finance build an IF sat between a Telegram approval and the node that writes to the ledger. Approving an invoice on your phone never updated anything. The audit had been silent about it for a week.
That one change took another build from 11 findings to 31, all of them real. An onboarding sequence — welcome email, contract, intake form, invoice, five provisioning steps, kickoff booking — where everything after the first email was reading its settings off the email server's reply.
So the day ended somewhere I did not expect: 121 reported, about half of them my tool's fault, the rest real and now fixed. Twenty-four builds, ninety-eight workflows, no open findings. I will not pretend that means flawless. It means nothing is known-broken, which is a smaller and much more honest claim.
The finance build deserves its own sentence, because it is the one that should worry you most. Its test suite passed 72 out of 72 the entire time. The fixtures handed each step both the AI's answer and the invoice in one object — a shape that cannot happen in production, where the AI call replaces the invoice. Every test passed. Not one invoice would have booked itself. The suite now feeds the real shape, and I reverted each fix one at a time to watch it fail before I trusted it again.
The lesson is not that static analysis is unreliable. It is that a tool which produces confident output deserves the same scepticism as a confident person — including when the confident person is you, and the tool is one you wrote. Audit the auditor before you act on it.
We now run that checker over every build before it goes near a client, and the results decide what we're willing to demo live versus what we'll only build to order. An engine with open findings doesn't get sold as ready — it gets fixed during the engagement that pays for it, and we say so out loud.
That's a slower way to sell. It is a considerably better way to still be in business in a year.
Want this handled for you?
This is the kind of work we do every day. Tell us what's slowing your business down on a free call.
Book a free call →