root-cause-debugging
Skill8 starsChanged 8 days agoMITView on GitHub
Finds the real cause of a bug before changing code, using a minimal reproduction, ranked hypotheses, one-variable experiments and bisection (git bisect, input bisection). Use when something is broken, failing, crashing, flaky, intermittent, behaving differently between environments, a test fails for unclear reasons, or an earlier fix did not work. Not for performance tuning without a defect or for designing new features.
9 other projects use a version of this.
Adopted by
Most recently taken up by
- alfonsusenrico/pakemtheir own version, first seen Oct 25, 2026
- plori-ai/skillstheir own version, first seen Oct 22, 2026
- yuchi-chang/no-capetheir own version, first seen Oct 8, 2026
- AL-JANEF/janef-forgetheir own version, first seen Sep 19, 2026
- AL-JANEF/janefskillstheir own version, first seen Sep 19, 2026
- adamentwistle/fable-skillstheir own version, first seen Sep 3, 2026
Used with
Projects with it also use ui-ux-quality.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
AL-JANEFSkillui-ux-quality
Make product flows clear and recoverable: primary action and next step obvious, forms with clear labels, validation timing, actionable errors, preserved input on failure, consistent navigation and terminology, and no hidden or surprising destructive actions. Use for user flows, forms, navigation, onboarding, dialogs, and interaction design.
Also in 3 projects that use this
Other versions9 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 9
- adamentwistle/fable-skills★ 98same name
- 05-deepak-patidar/claude-skills★ 4same name
- yuchi-chang/no-cape★ 2same name
- AL-JANEF/janef-forge★ 1same name
- AL-JANEF/janefskills★ 1same name
- HEMANTH-A-7/engram★ 1same name
- alfonsusenrico/pakem★ 0same name
- nolotus/skills★ 0same name
- plori-ai/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository60 other files it gives its agents.
- api-designSkill
- auth-implementationSkill
- background-jobsSkill
- building-agentsSkill
- caching-strategiesSkill
- ci-cd-pipelinesSkill
- cloud-cost-optimizationSkill
- codebase-onboardingSkill
- code-review-changesSkill
- concurrency-patternsSkill
- database-migrationsSkill
- database-schema-designSkill
- database-testingSkill
- data-pipelinesSkill
- data-privacy-retentionSkill
- dependency-upgradesSkill
- design-docsSkill
- design-systemsSkill
- dockerfilesSkill
- domain-driven-designSkill
- event-driven-architectureSkill
- file-storage-uploadsSkill
- frontend-securitySkill
- git-workflowSkill
- graphql-apisSkill
- grpc-servicesSkill
- incident-responseSkill
- infrastructure-as-codeSkill
- internationalizationSkill
- kubernetes-deploymentsSkill
- large-scale-migrationsSkill
- legacy-refactoringSkill
- llm-evalsSkill
- llm-integrationSkill
- mcp-serversSkill
- micro-frontendsSkill
- ml-experimentsSkill
- monorepo-managementSkill
- nosql-designSkill
- observabilitySkill
- orm-patternsSkill
- performance-profilingSkill
- postgres-operationsSkill
- rag-systemsSkill
- react-patternsSkill
- realtime-apisSkill
- resilience-patternsSkill
- search-integrationSkill
- security-auditSkill
- seo-and-ssrSkill
- sql-optimizationSkill
- system-designSkill
- test-strategySkill
- threat-modelingSkill
- typescript-patternsSkill
- unit-testingSkill
- verify-before-doneSkill
- web-accessibilitySkill
- web-performanceSkill
- writing-skillsSkill
The file
We split this skill into the rules it gives an agent
10 rules. 0 are common, 9 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 8 edited versions we read keep these.
9
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 9
Never change code to fix a bug you cannot explain.
- Distinctive: line 18
Not for: production outages where mitigation must come first (stabilize, then come back here), or performance work where nothing is …
- Distinctive: line 30
If you cannot reproduce it, do not guess.
- Distinctive: line 34
Narrow by bisection: when the search space is large:
- Distinctive: line 35
History: if it worked at some earlier commit, use git bisect (automate it with git bisect run).
- Very specific: line 39
Instrument where you are blind: Add logs at boundaries with a unique prefix (e.g.
- Distinctive: line 43
Clean up and report: Remove temporary instrumentation.
- Distinctive: line 60
If three fixes in a row have not worked, stop editing code.
- Distinctive: line 64
Write down every assumption you are making and verify each one.
- Distinctive: line 65
Ask whether the design itself is the problem (shared mutable state, wrong abstraction, hidden coupling).
“Common” is measured: kept by at least 6 in 10 of the 8 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Root-Cause Debugging
Never change code to fix a bug you cannot explain. Reproduce it, find the cause with evidence, and prove the fix with a test that failed before the fix and passes after it.
When to use
- An error, exception, crash, wrong output, failing test or regression.
- "Works on my machine", or works in one environment but not another.
- Intermittent or flaky failures.
- A fix was already tried and the bug came back or moved.
Not for: production outages where mitigation must come first (stabilize, then come back here), or performance work where nothing is actually wrong.
Workflow
- Capture the exact failure. Copy the full error message, stack trace, exit code, relevant log lines, and the exact command, request or steps that produced them. Write down expected vs actual behavior.
- Read the whole stack trace. Include every
Caused by:/ inner exception / wrapped error. The top frame is often library code; the first frame in the project's own code is usually where to start. The line where an error surfaces is where a bad value was used, not necessarily where it was produced. Reproduce it. Get a command that fails every time. Then shrink it: smallest input, fewest steps, a single test, for example:
pytest tests/test_orders.py::test_refund -xnpx vitest run src/cart.test.ts -t "applies discount"go test -run '^TestRefund$' ./ordersdotnet test --filter "FullyQualifiedName~RefundTests"
If you cannot reproduce it, do not guess. Collect more data (step 7) or ask the user for environment details, logs and exact steps.
- Check the boring causes first (table below). A large share of "impossible" bugs are stale builds, wrong branches, wrong config or a different dependency version.
- Write ranked hypotheses. List 2-5 candidate causes. For each: evidence for, evidence against, and the cheapest experiment that would confirm or rule it out. Start with the one that is most likely and cheapest to test.
- Experiment one variable at a time. Predict the result before running. If the result surprises you, your model of the system is wrong: update it before continuing. Revert experiments that did not help.
- Narrow by bisection when the search space is large:
- History: if it worked at some earlier commit, use
git bisect(automate it withgit bisect run). See references/git-bisect.md. - Input: halve the input file, payload, dataset or list of tests until you find the minimal failing case.
- Code path: disable half of the suspect code (early return, feature flag, stub) and see which half matters.
- Environment: diff a working and a failing environment (versions, env vars, config, OS, data) and apply half of the differences at a time.
- History: if it worked at some earlier commit, use
- Instrument where you are blind. Add logs at boundaries with a unique prefix (e.g.
DBG-1234), log types and lengths as well as values, use breakpoints and conditional breakpoints, or attach a tracer. See references/debugging-tools.md for per-language tools. Never log secrets or personal data. - State the root cause as a mechanism. "The cache key omits
tenant_id, so tenant B reads tenant A's entry" — not "bug in cache.py". Keep asking "why?" until you reach something you can fix that prevents this class of bug, not just this instance. - Write a failing regression test at the lowest level that still shows the bug. Run it and confirm it fails for the right reason (the assertion you expect, not an import or setup error).
- Fix the cause, then run the new test and the surrounding suite. Search the codebase for the same pattern (same call, same misuse) and fix or report the other places.
- Clean up and report. Remove temporary instrumentation. Tell the user: symptom, root cause, evidence, fix, regression test, other places affected, and anything you could not verify.
Check assumptions first
| Assumption | How to verify |
| You are running the code you think you are | Add a temporary log line and confirm it prints. Check git status, git branch --show-current, git log -1. Rebuild. Check which binary or interpreter runs: which/command -v (POSIX), where (Windows), python -c "import sys; print(sys.executable)". |
| Dependency versions match | Read the lockfile. npm ls <pkg>, pip show <pkg>, go list -m all, mvn dependency:tree, ./gradlew dependencies, dotnet list package, cargo tree. |
| Config and env vars are what you expect | Print the effective config at startup (redacted). Check precedence: defaults, files, env vars, CLI flags, remote config. |
| Nothing is cached or stale | Clean build (delete build/output dirs), rebuild containers with --no-cache, clear package caches, browser cache, CDN, service worker, memoization layers. |
| The data is what you think | Query the actual record or message. Do not reason from what the data "should" be. |
| Time, timezone and locale | UTC vs local, DST transitions, month-end, leap days, locale-specific number and date parsing. |
| Network path | DNS resolution, proxies, TLS, which host and port is actually hit (curl -v). |
| Permissions and identity | File permissions, OS user, service account, IAM role, token scopes. |
The three-strike rule
If three fixes in a row have not worked, stop editing code. Each failed fix is evidence that your hypothesis is wrong.
- Revert the failed attempts.
- Re-read the original evidence and the full stack trace.
- Write down every assumption you are making and verify each one.
- Ask whether the design itself is the problem (shared mutable state, wrong abstraction, hidden coupling).
- Tell the user what you have ruled out and what you plan to try next.
Intermittent bugs
| Symptom | Likely causes | Technique |
| Fails only under load or in parallel | Race condition, shared mutable state, pool exhaustion, missing lock or transaction | Repeat with parallelism: go test -race -count=100 ./..., pytest -n 8 (pytest-xdist) with --count=50 (pytest-repeat). Use race detectors: Go -race, ThreadSanitizer (-fsanitize=thread) for C/C++. |
| Depends on test order | State leaking between tests (globals, DB rows, env vars, singletons, mocks not reset) | Run in random order: pytest-randomly, jest --randomize, vitest --sequence.shuffle, go test -shuffle=on. Run the failing test alone, then with its neighbors. |
| Fails after hours or days | Memory, file handle, socket or connection leak; counter overflow; token or certificate expiry | Track resource counts over time; heap snapshots; check what expires. |
| Fails only in CI | Different OS, CPU count, timezone, locale, missing secrets, slower machine hitting timeouts, parallel jobs sharing resources | Diff the environments; run the CI container image locally; print env (redacted) in the CI job. |
| Disappears with logging or a debugger | Timing-sensitive race | Use low-overhead instrumentation (in-memory ring buffer dumped on failure), stress runs, race detectors. |
| Fails at certain times | Midnight, month or year boundaries, DST, leap years, cron overlap | Inject a clock and test with fixed times around the boundary. |
For an intermittent bug, "fixed" means the reproduction passes many repetitions (e.g. 100+ runs or a stress run) that previously failed at a known rate.
Anti-patterns
- Shotgun debugging — changing several things at once. When it starts working you do not know why, and you may have added new bugs.
- Fixing the symptom — swallowing the exception, adding a null check without knowing why the value is null, adding a retry or
sleepto hide a race, raising a timeout. These move the bug, they do not remove it. - Trusting the error location — the crash site is where the bad value was used. Trace the value backwards to where it was produced.
- Reasoning instead of running — reading code for an hour when a 30-second experiment would answer the question.
- Blaming the platform first — compiler, library and OS bugs exist but are rare. Rule out your own code and config first, and get a minimal reproduction before claiming one.
- Declaring victory early — the symptom disappeared once, so it must be fixed. Re-run the reproduction, and for flaky bugs, re-run it many times.
- Leaving debris — debug logs, commented-out code, disabled tests, temporary flags.
Done when
- You can state the root cause as a mechanism and point to the evidence.
- A regression test failed before the fix and passes after it.
- For intermittent bugs, the reproduction passes many repeated runs that failed before.
- The same pattern was searched for elsewhere and handled or reported.
- Temporary instrumentation is removed and the relevant test suite passes.
References
- references/git-bisect.md — read when the bug is a regression (it worked at some earlier commit or version).
- references/debugging-tools.md — read when you need a debugger, thread or heap dump, tracer, sanitizer or network tool for a specific language or runtime.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

