assumptions kill
every long debug session, without exception, traces back to a wrong assumption. the bug was always findable — you just weren't looking where it was because you "knew" it couldn't be there.
the pattern
here's how it always goes:
- something breaks
- you form a mental model of what's wrong
- you debug based on that model
- hours pass
- you discover the actual cause was in a part of the system you never questioned
- you realize you had an unexamined assumption that ruled out the correct hypothesis from the start
the 30-hour bug: i assumed the HTTP library faithfully forwarded my POST body through redirects. it didn't. that assumption meant i spent 30 hours looking at everything except the one thing that was broken.
hardware debugging is the same. i'll assume a component is working because it's new, or because "i just tested that." but "new" doesn't mean functional, and "just tested" might mean i tested under different conditions. dead components are invisible precisely because you assume they're alive.
types of hidden assumptions
"this part works"
the most common and most dangerous. you've tested a component, it passed, so you mentally mark it as "known good" and never revisit it. but "works" is context-dependent. something that works in isolation might fail in combination. something that worked yesterday might not work after a dependency update.
"this library does what the docs say"
libraries have bugs. docs have gaps. undocumented behaviors are everywhere. the assumption that third-party code is correct is reasonable — until it isn't. and when it isn't, you can waste enormous time because you're looking at your code while the bug is in theirs.
"the environment is the same"
"it works on my machine." different OS, different compiler version, different network configuration, different timezone, different locale. the assumption that your environment matches production (or matches your teammate's machine) is wrong more often than you'd think.
"i understand the system"
maybe the deepest one. you think you know how the system works, so you debug based on that understanding. but your mental model is always an approximation. the gap between your model and reality is where bugs hide.
how to systematically challenge assumptions
the assumption audit
when you're stuck, stop debugging and start listing assumptions. literally write them down:
- i assume the request is reaching the server
- i assume the database connection is live
- i assume this function returns what i think it returns
- i assume this config file is being read
- i assume the data is in the format i expect
then go through the list and verify each one. not "i'm pretty sure" — actually verify. print it, log it, test it directly. the one you're most confident about is often the one that's wrong, because high confidence is what prevents testing.
"what if the opposite were true?"
for each assumption, ask: what if this were wrong? what would the symptoms look like? do the symptoms match what i'm seeing? this is essentially hypothesis inversion — instead of trying to prove your theory right, try to prove it wrong. this is basic scientific method, but it's remarkably hard to do when you're emotionally invested in your current theory.
fresh eyes
someone who doesn't share your assumptions will question things you'd never think to question. this is why rubber duck debugging works — explaining to someone (or something) that doesn't have your context forces you to make your assumptions explicit. and explicit assumptions are testable.
it's also why pair debugging is often more effective than solo debugging. not because two people are smarter than one — they're not, necessarily — but because they have different assumptions.
the "proven wrong" log
i've started keeping a rough mental list of assumptions that turned out to be wrong. "HTTP redirects preserve the request body" is on that list now. "new components always work" is on it. "the docs are accurate" is on it. every entry on that list makes me slightly better at questioning similar assumptions in the future.
this is experience. this is what separates a senior debugger from a junior one — not intelligence, not speed, but a longer list of things they know not to assume.
beyond code
this applies directly to feedback-and-honesty. in relationships, the things you "know" about what someone else thinks or feels are assumptions. "they're upset because of X" — maybe. or maybe your model of them is wrong, and the real cause is something you'd never guess because you filtered it out before considering it.
it applies to confidence. sometimes the reason something isn't working in your life is that you're operating under an assumption about yourself that's wrong — "i'm not good at this," "this isn't for me," "this always fails." those are unexamined assumptions, and they're just as capable of sending you on a 30-hour detour as a bad HTTP redirect.
the uncomfortable truth
you can't eliminate assumptions. you need them to function — you can't verify every single thing from first principles every time you write a line of code. the skill isn't being assumption-free; it's knowing that your assumptions exist, knowing which ones are load-bearing, and being willing to zoom out and question them when things aren't working.
the best debuggers aren't the ones with no assumptions. they're the ones who hold their assumptions lightly.