Agent Skills: Systematic Bug Fixing

Systematically diagnose and fix bugs by reproducing issues, identifying root causes, implementing fixes, and preventing regressions. Use when debugging errors, fixing issues, or troubleshooting problems.

UncategorizedID: vapvarun/claude-backup/bug-fix

Skill Files

Browse the full folder contents for bug-fix.

Download Skill

Loading file tree…

skills/bug-fix/SKILL.md

Skill Metadata

Name
bug-fix
Description
Systematically diagnose and fix bugs by reproducing issues, identifying root causes, implementing fixes, and preventing regressions. Use when debugging errors, fixing issues, or troubleshooting problems.

Systematic Bug Fixing

A methodical approach to debugging that prioritizes understanding over guessing.

The Iron Law

NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST

Rule Zero: Verify Bug Reports Before Fixing

Bug reports, QA comments, and card descriptions can be WRONG. Verify first.

Before fixing any reported issue:

| Step | Action | |------|--------| | 1 | Read the actual code - Understand current implementation | | 2 | Verify the claim - Is it actually a bug or misunderstanding? | | 3 | Check official docs - Framework docs, API references, etc. | | 4 | Trace execution flow - Hook order, data flow, lifecycle | | 5 | Only fix if confirmed - Push back with evidence if not a real bug |

Common false positives:

  • Hook timing claims without understanding framework execution order
  • "Missing" features that exist but need to be enabled
  • "Bugs" that are actually intended behavior
  • Performance issues based on code reading, not profiling

If the bug report is wrong: Don't fix it. Comment back explaining why it's not actually a bug.

Attempting solutions without understanding the underlying problem leads to:

  • Wasted time (2-3 hours vs 15-30 minutes)
  • New bugs introduced
  • Original issue not actually fixed
  • Technical debt accumulation

When to Apply This Methodology

Use for any technical issue:

  • Test failures
  • Production bugs
  • Unexpected behavior
  • Performance problems
  • Build failures
  • Integration issues

Apply especially when:

  • Under time pressure
  • Quick fixes seem obvious
  • After multiple failed attempts
  • Understanding is incomplete

Four Sequential Phases

Phase 1: Root Cause Investigation

Complete these steps BEFORE proposing any fix:

1. Read Error Messages Thoroughly

# Don't skip past errors - they often contain solutions
# Note: line numbers, file paths, error codes

# BAD: Glancing at error
"Something about undefined..."

# GOOD: Full analysis
Error: Cannot read property 'name' of undefined
    at getUserData (src/services/user.js:45:23)
    at async handleRequest (src/api/handler.js:12:15)
# -> Issue is in getUserData at line 45, 'name' accessed on undefined value

2. Reproduce Consistently

// Document exact reproduction steps
/*
REPRODUCTION STEPS:
1. Login as test user (test@example.com)
2. Navigate to /dashboard
3. Click "Export" button
4. Select date range > 30 days
5. Click "Generate"
ERROR: "Cannot read property 'map' of undefined"

ENVIRONMENT:
- Browser: Chrome 120
- Node: 18.17.0
- OS: macOS 14.1
*/

3. Check Recent Changes

# What changed recently?
git log --oneline -20
git diff HEAD~5..HEAD -- src/

# Who touched the failing file?
git blame src/services/user.js

# When did it last work?
git bisect start
git bisect bad HEAD
git bisect good v1.2.3

4. Trace Data Flow Backward

// Work backward through call stack to find WHERE bad values originate

// Error occurs here:
function displayUser(user) {
  return user.name.toUpperCase(); // user is undefined!
}

// Trace back: Who calls displayUser?
function renderProfile() {
  const user = getCurrentUser(); // Returns undefined!
  return displayUser(user);
}

// Trace back: Why does getCurrentUser return undefined?
function getCurrentUser() {
  return userCache.get(userId); // userId is null!
}

// ROOT CAUSE FOUND: userId is null before cache lookup

5. Gather Evidence in Multi-Component Systems

// For systems with multiple layers, add diagnostic logging

// API -> Service -> Database
async function debugDataFlow() {
  console.log('[API] Request received:', req.body);

  const serviceResult = await service.process(data);
  console.log('[SERVICE] Result:', serviceResult);

  const dbResult = await db.save(serviceResult);
  console.log('[DB] Saved:', dbResult);

  // Identify which layer fails
}

Phase 2: Pattern Analysis

Before forming solutions:

1. Find Working Examples

// Look for similar code that WORKS in the codebase

// Broken:
const users = await fetchUsers();
users.map(u => u.name); // Fails when users is undefined

// Working (in another file):
const posts = await fetchPosts();
if (!posts || posts.length === 0) {
  return [];
}
posts.map(p => p.title); // Works because of guard clause

2. Compare Against References

// Read documentation/examples COMPLETELY

// API Documentation says:
// fetchUsers() returns Promise<User[] | null>
// Returns null when: user not authenticated, rate limited

// Your assumption was:
// fetchUsers() always returns User[]

// FIX: Handle null case
const users = await fetchUsers();
if (!users) {
  throw new AuthenticationError('Not authenticated');
}

3. List All Differences

| Aspect | Working Code | Broken Code |
|--------|--------------|-------------|
| Null check | Yes | No |
| Error handling | try/catch | None |
| Async handling | await | Missing await |
| Input validation | Validates | Trusts input |

Phase 3: Hypothesis and Testing

Apply scientific methodology:

1. Form Single Hypothesis

// State clearly: "I think X is the root cause because Y"

// HYPOTHESIS:
// The error occurs because fetchUsers() returns null when the
// session token expires, but we don't handle the null case.
// Evidence: Error only happens after ~30 minutes of inactivity
// (matching our 30-minute session timeout).

2. Test Minimally

// Make the SMALLEST possible change to test your theory
// One variable at a time

// TEST:
const users = await fetchUsers();
console.log('fetchUsers returned:', users, typeof users);
// If null: hypothesis confirmed
// If array: hypothesis wrong, form new hypothesis

3. Verify or Reject

// If test confirms hypothesis -> Phase 4
// If test rejects hypothesis -> Form new hypothesis

// DON'T: Add multiple fixes hoping one works
// DO: Test one thing, understand result, proceed logically

Phase 4: Implementation

Fix the ROOT CAUSE, not symptoms:

1. Create Failing Test Case

// Write test BEFORE fix
describe('fetchUsers', () => {
  it('handles null response from expired session', async () => {
    // Arrange
    mockSession.expire();

    // Act & Assert
    await expect(getUserList()).rejects.toThrow('Session expired');
  });
});

2. Implement Single Fix

// BAD: Multiple changes at once
async function getUserList() {
  try {
    const users = await fetchUsers();
    if (!users) throw new Error('No users');
    if (!Array.isArray(users)) users = [users];
    return users.filter(u => u.active).map(u => u.name);
  } catch (e) {
    console.error(e);
    return [];
  }
}

// GOOD: Address only the identified root cause
async function getUserList() {
  const users = await fetchUsers();
  if (!users) {
    throw new SessionExpiredError('Session expired, please login again');
  }
  return users.map(u => u.name);
}

3. Verify Fix

# Run specific test
npm test -- --grep "handles null response"

# Run related tests
npm test -- src/services/user.test.js

# Run full suite to check for regressions
npm test

4. Handle Failed Fixes

After 2 unsuccessful attempts:
  -> Return to Phase 1, gather more evidence

After 3+ failures:
  -> Question whether the architecture is fundamentally sound
  -> Discuss with team before continuing
  -> Consider if refactoring is needed

Red Flags - Return to Phase 1

Stop immediately if you think:

| Thought | Why It's Wrong | |---------|----------------| | "Quick fix for now, investigate later" | You'll never investigate later | | "Just try changing X and see if it works" | Random changes introduce new bugs | | "It's probably X, let me fix that" | "Probably" means you don't know | | "I don't fully understand but this might work" | Guaranteed to fail or cause new issues |

Common Bug Categories

Null/Undefined Errors

// Problem: Accessing property on null/undefined
user.profile.avatar.url

// Solutions:
// 1. Optional chaining
user?.profile?.avatar?.url

// 2. Guard clauses
if (!user?.profile?.avatar) return defaultAvatar;

// 3. Nullish coalescing
const url = user?.profile?.avatar?.url ?? defaultAvatar;

Async/Await Issues

// Problem: Missing await
async function loadData() {
  const data = fetchData(); // Missing await!
  console.log(data); // Promise, not data
}

// Problem: Parallel vs Sequential
// BAD: Sequential (slow)
const user = await fetchUser();
const posts = await fetchPosts();
const comments = await fetchComments();

// GOOD: Parallel (fast)
const [user, posts, comments] = await Promise.all([
  fetchUser(),
  fetchPosts(),
  fetchComments(),
]);

Race Conditions

// Problem: State changes during async operation
async function updateUser() {
  const user = this.state.user; // Captured at start
  const updated = await api.updateUser(user);
  this.setState({ user: updated }); // Overwrites changes made during await!
}

// Solution: Use functional update
this.setState(prevState => ({
  user: { ...prevState.user, ...updated }
}));

Off-by-One Errors

// Problem: Array bounds
for (let i = 0; i <= array.length; i++) { // <= should be <
  array[i]; // Undefined on last iteration
}

// Problem: Pagination
const page = 1;
const offset = page * pageSize; // Should be (page - 1) * pageSize

State Mutation

// Problem: Mutating state directly
const newArray = oldArray;
newArray.push(item); // Mutates oldArray too!

// Solution: Create new references
const newArray = [...oldArray, item];
const newObject = { ...oldObject, newProperty: value };

Debugging Tools

Browser DevTools

// Breakpoints
debugger; // Pauses execution

// Console methods
console.log(obj);
console.table(arrayOfObjects);
console.trace(); // Shows call stack
console.time('operation');
// ... operation
console.timeEnd('operation');

Node.js Debugging

# Inspect mode
node --inspect src/index.js

# Break on first line
node --inspect-brk src/index.js

# Debug tests
node --inspect-brk node_modules/.bin/jest --runInBand

Git Bisect

# Find the commit that introduced the bug
git bisect start
git bisect bad                 # Current commit is bad
git bisect good v1.2.0         # This version was good
# Git checks out middle commit
# Test it, then:
git bisect good  # or
git bisect bad
# Repeat until git finds the bad commit
git bisect reset  # Return to original state

Debugging Checklist

  • [ ] Can reproduce the issue consistently
  • [ ] Read complete error message and stack trace
  • [ ] Checked recent changes (git log/blame)
  • [ ] Identified root cause (not just symptoms)
  • [ ] Found working example for comparison
  • [ ] Formed testable hypothesis
  • [ ] Fix addresses root cause only
  • [ ] Created regression test
  • [ ] Tested edge cases
  • [ ] No new issues introduced
  • [ ] Documented the fix

Post-Fix Actions

  1. Add regression test - Prevent issue from returning
  2. Update documentation - If behavior was unclear
  3. Consider related code - Same bug elsewhere?
  4. Add monitoring - Detect if it happens again
  5. Share learnings - Help team avoid similar issues