| name | debugging-mindset |
| description | Use this skill when debugging code, diagnosing unexpected behavior, troubleshooting errors, or approaching a problem systematically. Trigger on keywords: debug, bug, error, not working, unexpected behavior, troubleshoot, investigate, root cause, why is this, something is wrong, failing test, crash. |
Debugging Mindset
Core Principle
Debug the system, not your assumptions.
Most bugs persist because developers debug what they think is happening instead of what's actually happening. Every assumption is a potential hiding place for a bug.
The Scientific Debugging Method
1. OBSERVE — What exactly is the symptom? (not interpretation, raw facts)
2. HYPOTHESIZE — What are the possible causes?
3. TEST — Design the smallest possible test to confirm/deny each hypothesis
4. CONCLUDE — What does the evidence tell you?
5. FIX — Address the root cause, not the symptom
6. VERIFY — Confirm the fix works and nothing else broke
7. PREVENT — Add a test that would catch this regression
Never skip step 7. Every bug is a test that doesn't exist yet.
Start Here: The Five Questions
Before writing a single line of debug code, answer these:
- What did I expect to happen?
- What actually happened? (exact error message, exact output)
- What changed recently? (last commit, dependency update, config change)
- Can I reproduce it reliably? (if not, it might be timing/state/environment)
- Is this the first time this happened? (regression vs new bug)
Answering these five questions often reveals the bug before you even look at code.
Divide and Conquer
For complex bugs in large codebases:
1. Identify the full path of execution involved
2. Pick the midpoint
3. Add a check there — does the data look correct?
4. If yes → bug is in second half. If no → bug is in first half.
5. Repeat until you've narrowed to a single function or line.
This is binary search for bugs. Cuts debugging time in half at each step.
Read the Error Message (Actually Read It)
Most developers skim error messages. Read them:
- What failed (error type)
- Where it failed (file, line, function name)
- Why it failed (message body)
- Stack trace — read bottom-up to find your code vs framework code
For cryptic errors: paste the exact error into the AI with context, not a paraphrase.
Common Bug Patterns
| Pattern | Signs | Fix |
|---|
| Off-by-one | Wrong count, first/last element skipped | Check loop bounds and index math |
| Null / undefined | "Cannot read property of undefined" | Add null guards, check API contracts |
| Async/await | Data appears empty, timing-sensitive | Ensure every async call is awaited |
| Stale state | Works sometimes, not always | Check state mutation, cache invalidation |
| Type mismatch | Unexpected behavior with numbers/strings | Check types explicitly, don't trust coercion |
| Environment diff | Works locally, fails in prod | Check env vars, dependency versions, OS differences |
| Race condition | Fails under load, works in isolation | Add locks, use atomic operations, review shared state |
Debugging Strategies by Context
Frontend / UI Bugs
- Open DevTools → Console (errors), Network (failed requests), Elements (DOM state)
- Check if the issue is data (wrong value) or rendering (correct value, wrong display)
- Isolate: reproduce in the smallest possible component
- Check browser compatibility if intermittent
Backend / API Bugs
- Check request payload first — is the input correct?
- Check database state — is the data what you expect?
- Trace through the service layer step by step
- Add temporary logging at key points to see actual values
Database / Query Bugs
- Run the query directly against the DB (not through ORM)
- Check actual data vs expected data
- Watch for N+1 queries (loop with individual DB calls)
- Check indexes for slow queries
Intermittent Bugs
- Add comprehensive logging — capture state at every step
- Look for shared mutable state
- Check for timing dependencies
- Reproduce under load (concurrency issues)
- Check for memory leaks or resource exhaustion
The Rubber Duck Method
Explain the bug out loud (to a rubber duck, a colleague, or an AI) as if they know nothing:
- What the code is supposed to do
- What it's actually doing
- Walk through the code line by line
The act of explaining forces you to examine every assumption. 60-70% of the time, you find the bug while explaining — before anyone responds.
When You're Stuck
After 20-30 minutes without progress:
- Take a break — 10 minutes away often produces the insight
- Rubber duck — explain the problem from scratch
- Question your most confident assumption — bugs often hide behind certainties
- Simplify — reduce to the minimal reproduction case
- Revert — if the bug is recent, git bisect or revert to last working state
- Ask for help — but prepare a clear problem statement first
Asking for Help Effectively
Context: [what the code is doing]
Expected: [what should happen]
Actual: [what is happening — exact error/output]
Tried: [what you've already attempted]
Suspicion: [your current best hypothesis]
After Fixing the Bug
- Write a test that would have caught this bug
- Document if the root cause was non-obvious
- Check for similar bugs elsewhere in the codebase
- Update the lessons log if it was a new class of mistake you want to remember
- Commit message should explain the root cause, not just the fix:
fix(auth): handle null session on token refresh
Previously crashed when session expired during token refresh.
Root cause: session.user was null after expiry but code assumed
it was always present. Added null guard and redirect to login.