Debugging Systematically
Finds the cause of a bug by reproducing it, forming one hypothesis at a time and testing each against evidence, instead of changing code until symptoms disappear. Use when something fails intermittently, works locally but not in production, or when several attempted fixes have not held.
- Skill name
debugging-systematically- Category
- coding
- Price
- Free
- Install
~/.claude/skills/debugging-systematically/SKILL.md- Tags
- debugging, troubleshooting, root cause, bisect
Debugging Systematically
Most time lost to a bug is spent changing things. The loop below spends it on narrowing instead, which terminates.
The loop
- [ ] 1. Reproduce it reliably
- [ ] 2. Write down the exact expected and actual behaviour
- [ ] 3. Bisect the space until the failure is in one component
- [ ] 4. Form ONE hypothesis that explains ALL the evidence
- [ ] 5. Design the cheapest observation that would disprove it
- [ ] 6. Run it. If the hypothesis survives, fix the cause and prove the fix
Step 4 is where this usually goes wrong. A hypothesis that explains the failure but contradicts one known fact is the wrong hypothesis, and pursuing it burns the afternoon.
Reproduce first
An intermittent bug that cannot be reproduced cannot be shown fixed. Widen until it happens, then narrow:
- What is different between a run that fails and a run that works? Input size,
time of day, first request after a deploy, a specific account.
- Does it survive a restart? Then it is state on disk or in a database, not in
memory.
- Does it happen on one instance only? Then compare configuration, not code.
If it truly cannot be reproduced, add logging that would distinguish the competing explanations and wait. That is slower than reproducing and faster than guessing.
Bisect the space, not just the history
git bisect is one axis. The others are usually quicker:
- Layer — does the failure appear at the database, the service, or the
client? Query the layer below directly.
- Input — halve the input until the failure disappears. The boundary is the
clue.
- Environment — run the production configuration locally, one variable at a
time.
- Time — when did it start? Correlate with deploys, data growth, and
certificate or credential expiry.
Testing a hypothesis
State it so it can be wrong: "the cache returns a stale row because invalidation runs before the write commits". Then find the observation that settles it — a log line, a query, a counter — and prefer the one that takes two minutes over the one that takes an hour.
Change one thing at a time. Two simultaneous changes and a working system tell you nothing about which mattered.
Before calling it fixed
- Explain the mechanism end to end. "It works now" is not a cause.
- Confirm the fix addresses the cause rather than the symptom that surfaced it.
- Reproduce the original failure with the fix reverted, then reapply it.
- Add the test that would have caught it.
- Look for the same mistake elsewhere in the codebase — it is rarely unique.
When stuck
Explain the problem out loud from the beginning, including what has been ruled out and how. Most stuck debugging sessions contain an assumption that was never checked, and stating it aloud is what exposes it.