Skip to main content
Guide contents
Beginner12 min

Bug Hunting and Debugging with Claude Code: A Practical Guide

A complete hands-on guide to debugging with Claude Code: analyzing stack traces, parsing server logs, fixing complex TypeScript compiler errors, auto-repairing tests, and eliminating performance bottlenecks.

Published:

1. Why Debugging with Claude Code Beats Traditional Manual Methods

Traditional software debugging is often an exhausting routine: developers spend hours navigating dense terminal stack traces, manually placing dozens of console.log statements or debugger breakpoints, and mentally correlating fragmented state across multiple modules.

Claude Code transforms this workflow fundamentally. Equipped with direct local filesystem access, the agent can trace an execution thread from the client interface through API routes down to database ORM queries in seconds.

mermaid
flowchart TD A["Symptom: Runtime crash or error log"] --> B["Claude Code CLI"] B --> C["Analyze Stack Trace & Identify Call Sites"] C --> D["Targeted Read & Grep across repository"] D --> E["Root cause localization"] E --> F["Formulate hypothesis & implement patch"] F --> G["Run automated test suite / build"] G -->|Pass| H["Clean git commit"] G -->|Fail| E

Comparing Manual Debugging to Claude Code

DimensionTraditional Manual DebuggingDebugging with Claude Code
Error LocalizationManually stepping through lines in an IDEAutonomous correlation of errors with repository context
Log TriageScanning thousands of plain-text log lines by eyeAutomated analysis of structured server logs via CLI pipelines
Cross-Module TracingKeeping complex 5-to-10 file call graphs in your headStep-by-step semantic data flow tracking
TypeScript ErrorsTemptation to bypass issues using as anyClean type narrowing and defensive validation
VerificationManually re-running dev servers and unit testsAutomated loop testing until 100% of test suites pass
Note

Claude Code does not eliminate the need for engineering judgment, but it accelerates the cycle from incident detection to root cause localization by 3x to 5x.


2. The Anatomy of an Ideal AI Bug Report

The speed and precision of problem resolution depend heavily on how thoroughly you formulate the initial prompt.

Vague Requests vs. Structured Bug Reports

Warning

Inefficient Request: "The app is broken, the signup form isn't working, please check what's wrong."

With this framing, the agent is forced to guess randomly across dozens of files, burning your context token window on speculation.

Tip

Professional Engineering Report: "When submitting the form at /register, the client receives an HTTP 500 status. The browser console outputs: TypeError: Cannot read properties of undefined (reading 'email'). The payload sends JSON with fields username and mailAddress. Check the validation schema in src/api/auth.ts and ensure field names align."

Four Essential Elements of an Actionable Bug Report

  1. Expected Behavior: What the application was supposed to do under normal conditions.
  2. Actual Behavior: The exact runtime error message, HTTP status code, or unexpected calculation result.
  3. Reproduction Steps: What buttons were clicked, what URL parameters were supplied, or what request payload was sent.
  4. Context & File Paths: Which page, component, or backend service experienced the failure.

3. Dissecting Stack Traces and Error Payloads

You can feed raw error payloads and stack traces directly into Claude Code. The agent autonomously strips away noisy external framework frames (node_modules) and focuses on your application code.

Passing a Raw Stack Trace

text
I am getting this runtime error when rendering the user table: TypeError: Cannot read properties of undefined (reading 'map') at UserTable (src/components/UserTable.tsx:34:22) at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:15486:18) at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:20103:13) What is causing this, and how should we properly handle loading and empty states?

How Claude Investigates the Incident

  1. Targeted Inspection: opens src/components/UserTable.tsx at line 34 using Read.
  2. Data Source Audit: checks component props and state hooks (useState, useQuery) to understand why the user array evaluates to undefined during rendering.
  3. Defensive Fix: adds optional chaining (users?.map(...)), a proper loading placeholder (Skeleton/Spinner), or safe default arrays (users = []).

4. Server Log Analysis via CLI Pipelines

For debugging backend crashes on local dev environments or staging servers, Claude Code integrates smoothly with standard Unix input/output pipes.

Pipelining Logs into Claude Code

bash
# Pipe the last 100 lines of an Nginx error log to Claude for instant diagnosis tail -n 100 /var/log/nginx/error.log | claude -p "Find critical errors and explain their root cause. Provide actionable fix instructions." # Diagnose container crashes directly from Docker docker logs --tail 200 api-service 2>&1 | claude -p "Analyze database connection failures and timeout exceptions."

Interactive Log File Audits

Inside an interactive session, you can direct the agent to saved log files:

text
Read logs/production-error.log and focus on entries with status 500 from the last two hours. Group related exceptions and trace which external service call failed.

Claude isolates recurring failure patterns, detects external API authentication drops, or pinpoints database connection pool exhaustion.


5. Strategic Instrumentation: Diagnostic Logging and Tracing

The hardest bugs are silent defects: the application throws no exceptions, but the resulting business data is wrong (for example, an order total displays $0.00 instead of $42.50).

In these situations, use strategic instrumentation.

Step-by-Step Investigation Workflow

  1. Instruct Claude to place diagnostic hooks:

    text
    The order total calculation is returning 0 for items with promo codes. Add targeted diagnostic logging to calculateOrderTotal and its call sites to log input arguments, discount factors, and return values.
  2. Reproduce the bug in your testing environment: execute the checkout flow with a promo code.

  3. Feed the diagnostic log output back to Claude:

    text
    Here is the diagnostic log from the checkout attempt: [DEBUG] Item subtotal: 42.50 [DEBUG] Promo code applied: 'SPRING20' -> parsed discount: '0.2' (string) [DEBUG] Applying formula: 42.50 * (1 - '0.2') -> NaN -> coerced to 0 What went wrong?
  4. Resolution and cleanup:

    Claude immediately spots the type mismatch (string rather than a number), fixes the discount parser, and automatically removes all temporary diagnostic logs.


6. Resolving Complex TypeScript Compiler Errors

TypeScript errors can be perplexing when dealing with generics, complex discriminated unions, or deeply nested objects.

The Danger of "Silencing" the Compiler

Rushing to patch errors with forceful type assertions (as unknown as TargetType) masks real bugs at build time, only to trigger runtime exceptions in production.

Instructing Claude for Clean Resolution

text
I am encountering this TypeScript compiler error in src/services/payment.ts:48: Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'. Fix this issue properly using strict type narrowing or safe fallback values. Do NOT use type assertions ('as') or 'any'.

Claude traces the variable's lifecycle and adds defensive checks to safeguard against undefined values.


7. Automated Test and Build Repair in a Loop

One of Claude Code's most impressive superpowers is running unattended in a "Run → Analyze → Fix → Verify" loop.

mermaid
flowchart TD A["Command: 'Fix all failing tests'"] --> B["Run npm test via Bash"] B --> C{"Did all tests pass?"} C -->|Yes| D["Report successful run"] C -->|No| E["Parse test runner failure reports"] E --> F{"Is the bug in code or test?"} F -->|In code| G["Fix application logic"] F -->|In test| H["Update stale test assertions"] G & H --> B

Ready-to-Use Auto-Repair Prompts


8. Identifying Performance Bottlenecks and Resource Leaks

Bugs aren't just crashes. Slow database queries, sluggish UI interactions, and memory bloat are severe performance bugs that degrade user experience.

Performance Audit Prompt

text
The /dashboard page takes over 6 seconds to load. Analyze the server-side data fetching and client components: 1. Check for N+1 query patterns in our Prisma calls. 2. Identify missing database indices on frequently queried foreign keys. 3. Look for unnecessary client component re-renders caused by unstable object references.

What Claude Audits During Performance Reviews:

  • N+1 Queries: replaces repeated loops of database calls with batch queries (IN operator or ORM include clauses).
  • React Memoization: flags heavy calculations missing useMemo or callback handlers missing useCallback.
  • Payload Bloat: introduces pagination (limit/offset) or selective projections (select: { id: true, name: true }) instead of loading unbounded tables.

9. Hands-on Workshop: Investigating a Production Defect

Let's walk through an actual defect: users report that applying a 15% discount coupon to a three-item shopping cart charges an incorrect total.

Step 1. Locating the Calculation Logic

Start Claude Code and locate the relevant module:

text
Find where the cart discount calculation is implemented and inspect the file.

Claude uses Grep for the keyword discount and discovers src/domain/cart.ts.

Step 2. Inspecting the Flawed Code

typescript
// Discovered inside src/domain/cart.ts: export function applyCoupon(total: number, discountPercent: number): number { return total - total * (discountPercent / 100); }

At first glance, the formula appears correct. However, JavaScript floating-point arithmetic produces precision artifacts: 100 - 100 * (15 / 100) yields 85.00000000000001, which causes payment processors like Stripe (which expect integer cents) to reject the payload.

Step 3. Formulating the Fix and Test Prompt

text
In src/domain/cart.ts, the applyCoupon function causes floating-point precision issues that fail payment validation. Refactor it to calculate prices in integer cents, add rounding via Math.round, and create a comprehensive unit test in src/domain/cart.test.ts covering edge cases.

Step 4. Verifying the Solution

The agent implements the integer-based calculation:

typescript
export function applyCouponInCents(totalCents: number, discountPercent: number): number { const discountAmount = Math.round(totalCents * (discountPercent / 100)); return Math.max(0, totalCents - discountAmount); }

Claude then runs npm test src/domain/cart.test.ts via Bash and confirms all test scenarios pass.


10. Self-Assessment and Final Debugging Checklist

Validate your understanding of debugging with Claude Code.

Review Questions

Tip

1. What is the most effective way to triage a staging server crash log using Claude Code?

Answer: Pipe the tail of the log file directly into Claude Code's print mode: tail -n 150 /var/log/app.log | claude -p "Find errors and diagnose causes".

Tip

2. Why should you explicitly instruct Claude not to use the as operator when fixing TypeScript errors?

Answer: Type assertions only silence compiler warnings; they do not safeguard against runtime crashes if the data is missing. Claude should be directed to implement proper type narrowing and defensive guards instead.

Tip

3. How should you direct Claude to fix a suite of failing tests after a major refactor?

Answer: Run Claude in an iterative loop: run tests, differentiate between obsolete test expectations and real regression bugs, patch the issues, and re-run until all suites pass.

Systematic Bug Hunting Checklist

  • Supply the 4 essential bug details: Expected Behavior, Actual Behavior, Reproduction Steps, and File Paths.
  • Pass full stack traces without truncation — Claude automatically filters out vendor noise.
  • Leverage Unix pipes (tail | claude -p) for fast server log diagnosis.
  • Require safe type narrowing instead of brute-force as any casting.
  • Instruct Claude to write regression unit tests for every fixed defect.
  • Clean up temporary diagnostic logs before committing code to the repository.
This guide is completely free. If it saved you an evening, you can support the project's growth.
Support the author