debugging

Systematically analyzes errors, identifies root causes, and suggests targeted fixes with regression safeguards.

SKILL.md

GitHub

Debugging Skill

When debugging issues, follow a systematic approach to identify root causes efficiently and propose safe fixes.

1. Understand the Problem

  • Read the full error message, stack trace, and any associated logs
  • Identify the exact file, line number, and function where the error originates
  • Determine whether the issue is a compile-time error, runtime exception, or logic bug
  • Reproduce the issue mentally by tracing the code path from entry point to failure
  • Check if the error message is from application code, a framework, or a third-party library

2. Check Common Issues First

  • Null/undefined references: Accessing properties on null, undefined, nil, or None values
  • Type errors: Passing wrong types, missing type coercion, incorrect generics
  • Race conditions: Concurrent access to shared state without synchronization
  • Off-by-one errors: Array bounds, loop conditions, pagination offsets
  • Import/dependency issues: Missing imports, circular dependencies, version conflicts
  • Configuration errors: Wrong environment variables, missing config files, incorrect connection strings
  • State management bugs: Stale state, mutation of supposedly immutable data, missing state updates

3. Analyze the Stack Trace

  • Read the stack trace bottom-up to find the originating call
  • Identify the boundary between application code and library/framework code
  • Look for the last application-level frame — that is usually where the bug lives
  • Check if the error is thrown directly or wrapped/re-thrown from a deeper call
  • For async code, check if the stack trace includes async boundaries (some frameworks lose context)

4. Investigate the Context

  • Read the function containing the error and its callers
  • Check recent changes to the affected files (git blame, git log)
  • Look for related issues or known bugs in the project's issue tracker
  • Check if the error occurs only under specific conditions (certain inputs, environments, timing)
  • Review test coverage for the affected code — missing tests often correlate with bugs

5. Identify the Root Cause

  • Distinguish between the symptom (where the error appears) and the cause (where the bug is)
  • Trace data flow backward from the failure point to find where the invalid state was introduced
  • Check preconditions: are function inputs valid? Are required fields populated?
  • For intermittent bugs, look for timing dependencies, caching issues, or non-deterministic behavior
  • For regression bugs, identify what changed (new code, dependency update, config change)

6. Propose a Fix

  • Fix the root cause, not just the symptom
  • Explain why the fix works, not just what it changes
  • Keep the fix minimal — change only what is necessary to resolve the issue
  • Preserve existing behavior for all paths that are not affected by the bug
  • If the fix requires a design change, explain the tradeoff and alternatives considered

7. Prevent Regressions

  • Write a test that reproduces the bug and verifies the fix
  • The test should fail without the fix and pass with it
  • Check if similar patterns exist elsewhere in the codebase that might have the same bug
  • Consider adding runtime validation or assertions at the boundary where the bug entered
  • If the bug was caused by a missing null check, consider enabling stricter null checking project-wide

8. Communicate Findings

  • Summarize: what was the error, what caused it, and how it was fixed
  • Include the file paths and line numbers of the changes
  • Note any follow-up tasks (e.g., refactoring to prevent similar issues, adding monitoring)
  • If the fix is a workaround, document the ideal solution and create a follow-up ticket