name: bug-hunter description: | This skill should be used when the user reports "error", "bug", "not working", "failing tests", "unexpected behavior", "investigate issue", or describes something broken or malfunctioning. Use for systematic debugging, root cause analysis, and problem diagnosis. Do NOT use for implementing new features, writing tests, or making design decisions. version: 0.1.0
Bug Hunter: Debugging & Root Cause Analysis
Purpose
Systematically investigate errors, diagnose problems, identify root causes, and propose fixes through methodical debugging approaches.
When to Use This Role
✅ USE when:
- Application presents errors
- Unexpected behavior occurs
- Tests fail without clear reason
- Performance degrades
- Need root cause analysis
❌ DO NOT USE when:
- Implementing new feature (use implementer)
- Error is obvious with clear fix (fix directly)
- Writing preventive tests (use tester)
- Design decisions needed (use architect)
Debugging Methodology
1. Reproduction
Establish consistent reproduction steps:
Reproduction checklist:
- Can error be reproduced consistently?
- What are exact steps to trigger?
- Does it happen in specific environment only?
- Is there a stack trace or error log?
- What changed since it last worked?
Document reproduction:
Steps to Reproduce:
1. Start application: npm start
2. Navigate to /login
3. Enter valid credentials
4. Click login button
5. Observe: "TypeError: Cannot read property 'token' of undefined"
Environment:
- OS: macOS 14.1
- Node: 18.17.0
- Browser: Chrome 120
Frequency: 100% (every login attempt)
2. Isolation
Narrow down the problem source:
Isolation techniques:
Binary Search:
Disable half the code/features
Problem still occurs?
Yes: Problem is in enabled half
No: Problem is in disabled half
Repeat until isolated
Strategic Logging:
console.log('[DEBUG] Input:', input)
console.log('[DEBUG] After transformation:', transformed)
console.log('[DEBUG] Before validation:', data)
console.log('[DEBUG] Final result:', result)
Debugging Tools:
// Breakpoint in code
debugger; // Execution pauses here
// Conditional breakpoint
if (userId === 'problematic-id') {
debugger;
}
Git Bisect:
# Find commit that introduced bug
git bisect start
git bisect bad # Current commit is broken
git bisect good v1.0.0 # v1.0.0 was working
# Git tests commits, you mark good/bad
# Until culprit commit found
3. Diagnosis
Analyze to find root cause:
Questions to ask:
- What changed since last working version?
- Which files were modified?
- Were dependencies updated?
- Is it logic error, state issue, or environment?
- Are there assumptions that don't hold?
Stack Trace Analysis:
Error: Cannot read property 'name' of undefined
at getUserName (user.service.ts:42)
at renderProfile (profile.component.tsx:18)
at onClick (button.component.tsx:10)
Analysis:
1. Button clicked → button.component:10
2. Calls renderProfile → profile.component:18
3. Calls getUserName → user.service:42
4. Tries to access user.name but user is undefined
Root Cause: getUserName() returns undefined when user not in cache
Fix: Add null check or fetch user if not cached
4. Fix & Verification
Fix root cause, not symptoms:
Fix principles:
- Address root cause, not just symptoms
- Add test to prevent regression
- Document why problem occurred
- Verify fix doesn't break anything else
Verification steps:
- Implement fix
- Verify original issue resolved
- Run full test suite
- Check for side effects
- Test in same environment where bug occurred
Common Debugging Patterns
Pattern 1: Add Logging
// Before (mysterious failure)
function processUser(userId: string) {
const user = getUser(userId)
return user.profile.avatar
}
// After (reveals problem)
function processUser(userId: string) {
console.log('[DEBUG] Input userId:', userId)
const user = getUser(userId)
console.log('[DEBUG] Retrieved user:', user)
if (!user) {
console.error('[DEBUG] User not found!')
throw new NotFoundError(`User ${userId} not found`)
}
console.log('[DEBUG] User profile:', user.profile)
if (!user.profile) {
console.error('[DEBUG] User has no profile!')
throw new Error(`User ${userId} has no profile`)
}
return user.profile.avatar
}
Pattern 2: Inspect State
// Debug React state issues
useEffect(() => {
console.log('[STATE] userId:', userId)
console.log('[STATE] user:', user)
console.log('[STATE] isLoading:', isLoading)
console.log('[STATE] error:', error)
}, [userId, user, isLoading, error])
Pattern 3: Isolate with Unit Test
// Reproduce issue in isolated test
it('should handle missing user gracefully', () => {
const mockDb = {
findUser: jest.fn().mockResolvedValue(null)
}
const service = new UserService(mockDb)
// This should throw NotFoundError, but crashes instead
expect(() => service.getUserName('missing-id'))
.toThrow(NotFoundError)
})
Pattern 4: Check Assumptions
// Assumption: req.user always exists after auth middleware
function getProfile(req, res) {
// DEBUG: Validate assumption
console.assert(req.user, 'req.user should exist after auth')
if (!req.user) {
console.error('[DEBUG] req.user is undefined!')
console.error('[DEBUG] req.headers:', req.headers)
console.error('[DEBUG] req.cookies:', req.cookies)
throw new Error('User not authenticated')
}
return res.json(req.user.profile)
}
Debugging Tools & Techniques
Console Logging
// Structured logging
console.log('[MODULE:FUNCTION] Variable:', value)
console.log('[UserService:login] Credentials:', { email, hasPassword: !!password })
// Object inspection
console.dir(complexObject, { depth: null })
// Table view for arrays
console.table(users)
// Performance timing
console.time('database-query')
await db.query(...)
console.timeEnd('database-query')
Debugger Statements
// Pause execution
function complexCalculation(input) {
debugger; // Execution pauses, can inspect variables
const step1 = transform(input)
debugger; // Check step1 value
const step2 = validate(step1)
debugger; // Check step2 value
return step2
}
Network Inspection
// Log HTTP requests
fetch('/api/users')
.then(res => {
console.log('[DEBUG] Response status:', res.status)
console.log('[DEBUG] Response headers:', res.headers)
return res.json()
})
.then(data => {
console.log('[DEBUG] Response data:', data)
})
.catch(error => {
console.error('[DEBUG] Request failed:', error)
})
Database Query Logging
// Log SQL queries
db.on('query', (query) => {
console.log('[DB] Query:', query.sql)
console.log('[DB] Params:', query.bindings)
console.log('[DB] Duration:', query.duration + 'ms')
})
Example Debugging Session
Problem: "Login always fails with 'Invalid token'"
1. Reproduction
Steps:
1. POST /api/login with valid credentials
2. Receive 200 OK with token
3. POST /api/profile with token in Authorization header
4. Receive 401 Unauthorized: "Invalid token"
Consistent: Yes, 100% reproduction
2. Isolation
Added logging to middleware:
// auth.middleware.ts
export function requireAuth(req, res, next) {
console.log('[AUTH] Headers:', req.headers)
const authHeader = req.headers.authorization
console.log('[AUTH] Auth header:', authHeader)
if (!authHeader) {
console.log('[AUTH] No auth header!')
return res.status(401).json({ error: 'No token' })
}
const token = authHeader.split(' ')[1]
console.log('[AUTH] Extracted token:', token)
const decoded = verifyToken(token)
console.log('[AUTH] Decoded:', decoded)
if (!decoded) {
console.log('[AUTH] Token verification failed!')
return res.status(401).json({ error: 'Invalid token' })
}
req.user = decoded
next()
}
Output:
[AUTH] Headers: { authorization: 'Bearer undefined' }
[AUTH] Auth header: Bearer undefined
[AUTH] Extracted token: undefined
[AUTH] Decoded: null
[AUTH] Token verification failed!
3. Diagnosis
Token is undefined in Authorization header!
Checked login response:
// auth.controller.ts
export async function login(req, res) {
const token = generateToken(user.id, user.email)
console.log('[LOGIN] Generated token:', token) // Token exists!
res.json({
message: 'Login successful',
access_token: token // ← Sent as 'access_token'
})
}
Checked client code:
// client.ts
const response = await fetch('/api/login', { ... })
const data = await response.json()
// BUG: Looking for 'token' but server sends 'access_token'
localStorage.setItem('token', data.token) // ← data.token is undefined!
Root Cause: Client expects token but server sends access_token
4. Fix
Option A: Change server to send token (breaks other clients)
Option B: Change client to read access_token (correct fix)
// client.ts - Fixed
const response = await fetch('/api/login', { ... })
const data = await response.json()
localStorage.setItem('token', data.access_token) // Fixed!
5. Verification
1. Login: ✓ Token stored correctly
2. Profile request: ✓ Returns user data
3. All tests: ✓ Passing
4. No side effects: ✓ Other endpoints unaffected
6. Prevention
Added test to prevent regression:
it('should store access_token from login response', async () => {
const response = { access_token: 'test-token-123' }
// Simulate login
handleLoginResponse(response)
expect(localStorage.getItem('token')).toBe('test-token-123')
})
Recording Bug Fixes
Store in memory for future reference:
memory_store(
project_id=current_project,
type="bug_fix",
title="Login token undefined issue",
content=`
Bug: Login always fails with "Invalid token"
Root Cause:
- Client expected 'token' field in login response
- Server sends 'access_token' field
- Mismatch caused undefined token
Solution:
- Updated client to read 'access_token' field
- Added test to prevent regression
Files Changed:
- client/auth.ts: Fixed token extraction
- client/auth.test.ts: Added regression test
Prevention:
- Test now validates response structure
- Documented API contract in README
`,
metadata={
"severity": "high",
"type": "authentication",
"files": ["client/auth.ts", "client/auth.test.ts"]
}
)
Debugging Checklist
- Error reproduced consistently
- Reproduction steps documented
- Stack trace analyzed
- Recent changes reviewed
- Problem isolated to specific code
- Root cause identified (not just symptom)
- Fix implemented
- Regression test added
- Full test suite passes
- No new bugs introduced
- Bug fix documented in memory
Common Bug Categories
Logic Errors
Symptoms: Wrong output, incorrect calculations Approach: Trace execution flow, check assumptions
State Issues
Symptoms: Inconsistent behavior, race conditions Approach: Log state changes, check timing
Null/Undefined Errors
Symptoms: "Cannot read property of undefined" Approach: Add null checks, validate assumptions
Async Issues
Symptoms: Timing problems, race conditions Approach: Check promise handling, add awaits
Environment Issues
Symptoms: Works locally, fails in production Approach: Check env vars, dependencies, configs
Key Principles
- Reproduce First - Can't fix what you can't reproduce
- Isolate Systematically - Narrow down methodically
- Fix Root Cause - Not just symptoms
- Add Regression Test - Prevent recurrence
- Document Findings - Help future debugging
- Verify Thoroughly - Ensure no side effects
- Learn from Bugs - Update practices to prevent similar issues
Summary
As debugger:
- Reproduce issues consistently
- Isolate problems systematically
- Analyze to find root cause
- Fix cause, not symptoms
- Add tests to prevent regression
- Document findings in memory
- Verify fixes thoroughly
Focus on methodical investigation, root cause analysis, and preventive measures for effective debugging.