The small bugs that end up as production disasters almost always live in code that only runs after something else has already failed.
Not the happy path. The except branch, the timeout handler, the fallback.
Three properties make that code uniquely dangerous.
It is effectively untested. To exercise it you have to simulate a provider that times out mid-request, or a callback that arrives twice while the first one is still open. Most suites never build that harness, so the branch ships unread. It compiles, so it looks fine.
It fires under correlation. Error paths do not get one request at a time: they get every in-flight request at once, because the thing that failed failed for all of them. A branch that has been wrong for months is suddenly wrong a few thousand times inside a minute.
And it usually has write authority over state that matters: mark a payment failed, release a hold, lift the lock on a withdrawal, flip a verification to rejected. One wrong mapping in there does not hand a user a wrong number. It writes records that downstream ledgers, payouts and compliance reviews then treat as settled truth.
So in payment and crypto work I give error paths the same weight as the main flow. A timeout becomes unknown, never failed: unknown is a state you can reconcile, failed is a state other systems act on. Terminal states get set by a reconciliation pass against the provider, not by a local exception handler guessing. And every fallback branch has to be reachable in tests through injected failure, otherwise it is not a fallback, it is a rumour.
The habit worth keeping is small: when you read a diff, check what the code does while its dependency is down. That branch has the widest blast radius and the least review.
Worth knowing which terminal states your error handlers can write on their own...