This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.
Two bugs, one story. A parser that failed on every real call, plus the test that certified it as working for two review rounds. The second one is the one worth reading about.
What the code does
I was writing adapters for a protocol indexer. Each adapter has a Receipt parser: it receives the on-chain state changes from one transaction and produces a structured outcome, "this account swapped 100 of token A for 98 of token B". Downstream consumers trust that outcome. If the parser picks the wrong movement out of the transaction, the system reports a swap that never happened, with no error anywhere.
The tests ran against live mainnet, which is where this starts.
Bug one: the test that could not fail
The end-to-end test for one adapter looked roughly like this:
if (halted) {
expect(index).toBe(1) // the call reverted on chain, fine
} else {
expect(result).toEqual(...) // the call succeeded, check the payload
}
The reasoning was sensible. This is a live chain, the contract call might legitimately revert depending on pool state, so the test tolerates a revert instead of failing the build on someone else's liquidity.
Read it again. There is no input that makes this test fail. Success gets checked. Failure gets accepted. The assertion has no opinion.
Nine cases against Monad mainnet, all green, through two rounds of review. What they were actually reporting was my own parser throwing on every single call. The halt the test tolerated was never the chain rejecting anything. It was my code.
The reviewer did not catch it. I did not catch it. The suite was green, which is what we both looked at.
Bug two: the parser underneath
With the tolerance removed the real bug surfaced immediately, a one-liner of the worst kind:
const leg = transfers.find(t => /* right endpoints, right amount, not our own token */)
.find() returns the first match. The predicate described a shape that any ERC-20 transfer of the right size could satisfy. So in a transaction carrying two structurally identical movements, the parser reported whichever came first in the log.
Two ways that goes wrong. I reproduced both:
- Put a decoy transfer with the same shape ahead of the real one and the decoy is reported as the outcome asset.
- Duplicate the real movement and two genuine transfers collapse into one outcome, while coverage still looks complete.
Neither raises anything. You get a plausible, wrong answer.
The fix is a rule rather than a patch: filter the candidates, then require exactly one. Zero keeps the existing missing-evidence error. Two or more throws and names the count. Ambiguity becomes a loud failure instead of a coin flip, which is the only correct behavior when the data genuinely cannot distinguish two movements.
Why I care more about the test than the parser
The parser bug is ordinary. .find() where you meant "the only one" is a mistake every codebase has. Once you see it you fix it in a minute.
The test bug is the interesting one, because it consumed the evidence I was using to judge the parser. A green suite is what I hand a reviewer. A branch in the assertion means the suite cannot tell the happy path from the exact failure the code has, so "green before submit" becomes a sentence nobody checked.
Three things I now do because of it.
Any if (failure) {...} else {...} in a test is unverified until probed. So is any comment excusing a failure mode. When a test says a failure is acceptable because external state might reject the call, go find out which one actually happened. Dump the raw trace once, then assert the single real behavior and let it fail loudly if the world changes.
Grep for first-match selection. .find(, [0], .at(0), .shift(). For each one, ask what stops a second, equally valid item from matching. If the predicate cannot name something fixed, it is guessing.
Prove the new assertion fails without the fix. Be careful how you undo it. This one bit me a second time. To show an assertion catches the bug you revert the source and run the suite. I used git checkout -- <file> to undo the experiment, but that file also held the round's real work, so my new assertions vanished and the next run went green for an entirely different reason. Caught by diffing the working tree, not by the suite. So: toggle only the file the experiment needs, never one carrying the change, then capture the failing output to a file the moment it fails, because you cannot reproduce it once the state is restored.
The shape of both bugs
Neither of these was a crash. Nothing threw, nothing logged, no monitor fired. One produced a wrong answer that looked like a right answer. The other produced a green test that looked like a passing test.
That is the class of bug I have started looking for first, because it is the class that survives review. A crash gets fixed the day it happens. A confident wrong answer ships, then it gets built on.
Written with AI assistance (Claude, Anthropic). The bugs, the reproductions and the review history are from my own work on a real open source adapter. Both defects were reproduced from both directions, the decoy and the duplicate, before the fix was submitted. The corrected assertions were confirmed failing against the unpatched parser.
Top comments (0)