You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You have a reproduction and a suspect cause ("I think it's the cache", "the
timeout is too low") and you are about to "try a fix" to see if it helps. Also
applies when several suspects compete and you must pick what to investigate next.
Do this
State the hypothesis as a specific mechanism, written down: "X causes the
failure because Y" — not "something with the cache". A hypothesis you cannot
write down is a hunch; go gather more evidence first.
Derive a testable prediction the hypothesis forces: "if this is the cause,
then the failure disappears with the cache disabled / the log shows a stale
entry at T / the request carries value V". A hypothesis with no prediction
that could come out false is untestable — replace it.
Run the cheapest experiment that can falsify the prediction, before any code
change. Ordered by cost: read existing logs/evidence → add one log
line/assertion → toggle one flag or config → stub one component → change code.
Change exactly one variable per experiment; compare against the unmodified
reproduction as baseline.
Record each hypothesis and its outcome (confirmed / falsified / inconclusive)
in a running log — the issue comment, PR description, or a scratch file kept
for the session. This prevents re-testing falsified ideas and makes handoffs
and "back to it tomorrow" cheap.
When two hypotheses remain, test the one that is cheaper to falsify first —
a cheap falsification eliminates a branch at low cost, regardless of which
one you believe more.
Only after the mechanism is confirmed, write the fix — and predict what the
fix changes so the reproduction from [debugging-methodology-reproduce-first]
can verify exactly that.
Edge cases
Case
Then
The fix "works" but you never confirmed the mechanism
Verify before closing: re-introduce the original condition and confirm the failure returns, or trace the mechanism end-to-end in evidence (logs/values). A fix that works for unknown reasons masks symptoms and leaves the cause live
Experiment is inconclusive (failure is intermittent)
Make the observation statistical — N runs per arm, per [debugging-concurrency-intermittent-failures] — before drawing any conclusion
Every hypothesis you can think of is falsified
Your model of the system is wrong somewhere upstream. Return to evidence gathering: widen what you observe ([debugging-signals-logs-and-correlation]) or bisect to relocate the fault ([debugging-methodology-isolate-by-bisection])
Testing the hypothesis requires touching prod
Prefer a read-only prediction (something already in logs/metrics that must be true if the hypothesis holds); active prod experiments require owner approval and a rollback plan
Hypothesis confirmed but the fix belongs to another domain (slow query, infra limit)
Record the confirmed mechanism, then route the fix to the owning domain — e.g. a slow SQL statement goes to wiki/databases/query-optimization/reading-execution-plans.md
Instead of
If you are about to
Do this instead
Why
Change several suspicious things at once and rerun
One variable per experiment
If the batch flips the result you cannot attribute it; if it doesn't, you have falsified nothing
Conclude "the fix worked, so that was the cause"
Confirm the mechanism: re-introduce the condition and watch the failure return, or explain via evidence why the fix closes it
Rebuilds, cache resets, and restarts ride along with "fixes" and mask the real cause
Keep hypotheses in your head across a long session
Write the hypothesis log as you go
Untracked falsified hypotheses get re-tested; sessions and handoffs lose the search state
Start with the most invasive experiment (rewrite the suspect module)
Run the cheapest falsifying experiment first
Most hypotheses die cheap; invasive experiments add new variables and new bugs