By Sagar Shankaran, Founder of CallSphere
How to use Claude Code to debug production issues — analyzing stack traces, tracing code paths, reproducing bugs, fixing root causes, and preventing regressions.
Key takeaways
Debugging is arguably Claude Code's strongest use case. The SWE-bench benchmark — where Claude Code scored 80.9% — is essentially a debugging benchmark: given a bug report, find and fix the issue in a real codebase.
Claude Code's debugging advantage comes from its ability to:
The most common debugging scenario: you have an error stack trace from production.
flowchart LR
USER(["User message"])
LOOP{"messages.create<br/>agent loop"}
THINK["Extended thinking<br/>optional"]
TOOL{"stop_reason<br/>tool_use?"}
EXEC["Execute tool<br/>append tool_result"]
DONE(["stop_reason<br/>end_turn"])
USER --> LOOP --> THINK --> TOOL
TOOL -->|Yes| EXEC --> LOOP
TOOL -->|No| DONE
style LOOP fill:#4f46e5,stroke:#4338ca,color:#fff
style THINK fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style DONE fill:#059669,stroke:#047857,color:#fff
Debug this production error:
TypeError: Cannot read properties of undefined (reading 'map')
at OrderSummary (src/components/OrderSummary.tsx:47:28)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14985:18)
at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:17811:13)
This happens intermittently — only for some orders.
Claude Code follows a systematic debugging process:
[Read] src/components/OrderSummary.tsx — Read line 47 and surrounding context
[Read] src/types/order.ts — Check the Order type definition
[Grep] "OrderSummary" in src/ — Find where this component is rendered
[Read] src/pages/orders/[id].tsx — Read the parent component
[Read] src/api/orders.ts — Read the API call
Claude Code identifies: The order.lineItems field is undefined when the order has been created but payment has not been completed. The API returns a partial order object in this state, and the component assumes lineItems is always an array.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
// Before (line 47 of OrderSummary.tsx)
const total = order.lineItems.map(item => item.price * item.quantity)
.reduce((sum, val) => sum + val, 0);
// After — Claude Code's fix
const total = (order.lineItems ?? [])
.map(item => item.price * item.quantity)
.reduce((sum, val) => sum + val, 0);
Claude Code also fixes the root cause at the API level:
// In the API serializer — ensure lineItems is always an array
function serializeOrder(order: OrderRecord): OrderResponse {
return {
...order,
lineItems: order.lineItems ?? [], // Never return undefined
};
}
And adds a test:
test("OrderSummary handles order with no line items", () => {
const partialOrder = { id: "123", status: "pending", lineItems: undefined };
render(<OrderSummary order={partialOrder as any} />);
expect(screen.getByText("$0.00")).toBeInTheDocument();
});
Performance issues often stem from N+1 queries. Claude Code can diagnose them:
The /api/teams endpoint is slow. Response time is 2-3 seconds for a user
with 10 teams. The database shows 120+ queries per request.
Help me find and fix the N+1 query.
Claude Code's investigation:
[Read] src/api/teams.ts — Read the endpoint handler
[Read] src/services/team.ts — Read the service layer
[Grep] "findMany|find\(" in src/services/team.ts — Find all queries
Diagnosis: The service fetches teams, then loops through each team to fetch members, then for each member fetches their profile. Three levels of nested queries.
# Before: N+1+1 query pattern
async def get_teams_for_user(user_id: str, db: AsyncSession):
teams = await db.execute(select(Team).where(Team.members.any(id=user_id)))
result = []
for team in teams.scalars():
members = await db.execute( # N queries
select(User).where(User.team_memberships.any(team_id=team.id))
)
for member in members.scalars():
profile = await db.execute( # N*M queries
select(Profile).where(Profile.user_id == member.id)
)
return result
# After: Single query with eager loading
async def get_teams_for_user(user_id: str, db: AsyncSession):
result = await db.execute(
select(Team)
.where(Team.members.any(id=user_id))
.options(
selectinload(Team.members).selectinload(User.profile)
)
)
return list(result.scalars().unique().all())
Race conditions are notoriously difficult to debug. Claude Code's approach:
We have a bug where two users can book the same appointment slot simultaneously.
The booking endpoint checks availability before creating the booking, but
under load, duplicates are created.
Claude Code reads the booking service:
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
# Current code — race condition between check and insert
async def book_appointment(slot_id: str, user_id: str, db: AsyncSession):
slot = await db.execute(
select(AppointmentSlot).where(AppointmentSlot.id == slot_id)
)
slot = slot.scalar_one_or_none()
if not slot:
raise HTTPException(404, "Slot not found")
if slot.booked_by is not None: # Check
raise HTTPException(409, "Slot already booked")
slot.booked_by = user_id # Act — another request can book between check and act
await db.commit()
Claude Code's fix uses database-level locking:
# Fixed — uses SELECT FOR UPDATE to prevent concurrent booking
async def book_appointment(slot_id: str, user_id: str, db: AsyncSession):
async with db.begin():
result = await db.execute(
select(AppointmentSlot)
.where(AppointmentSlot.id == slot_id)
.with_for_update() # Lock the row
)
slot = result.scalar_one_or_none()
if not slot:
raise HTTPException(404, "Slot not found")
if slot.booked_by is not None:
raise HTTPException(409, "Slot already booked")
slot.booked_by = user_id
# Commit happens when the async with block exits
Plus a unique constraint for defense in depth:
ALTER TABLE appointment_slots ADD CONSTRAINT unique_booking
UNIQUE (id, booked_by) WHERE booked_by IS NOT NULL;
Our Node.js backend's memory usage grows steadily and crashes after ~12 hours.
Help me find the memory leak.
Claude Code's systematic approach:
[Grep] "addEventListener|on\(" in src/ — Find event listeners
[Grep] "setInterval|setTimeout" in src/ — Find timers
[Grep] "new Map|new Set|cache" in src/ — Find growing collections
[Read] src/services/cache.ts — Examine caching logic
Common findings:
This bug was introduced recently. Use git log to find commits in the last
2 weeks that touched src/services/payment.ts, then help me identify
which commit introduced the issue.
Write a failing test that reproduces this bug:
[describe the bug]
Then fix the code to make the test pass.
This is the most reliable debugging pattern — it ensures the fix actually addresses the problem and creates a regression test.
Here are the last 50 lines of the backend logs during the error.
Identify the sequence of events that led to the failure.
[paste logs]
The /api/users endpoint works correctly but the /api/teams endpoint returns
a 500 error with the same query parameters. Both use the same service pattern.
Compare the two endpoints and find what's different.
| Situation | Prompt |
|---|---|
| Stack trace | "Debug this error: [paste stack trace]" |
| Intermittent bug | "This happens only sometimes: [describe]. What conditions could cause this?" |
| Performance issue | "This endpoint takes 3 seconds. Find the bottleneck." |
| Data corruption | "Some records have invalid data. Trace how data flows from input to database." |
| Integration failure | "The webhook from [service] is being received but not processed correctly." |
Include the error message, stack trace, when it happens, and what you have already tried. More context leads to faster diagnosis.
Before making any changes, list the top 3 most likely causes of this bug
and how you would verify each one.
Find and fix the root cause. Do not just add a null check if the real issue
is that the data should never be null.
After fixing the bug, write a test that would have caught it.
The test should fail before the fix and pass after.
Now search the rest of the codebase for the same pattern that caused this bug.
Are there other places with the same vulnerability?
Claude Code transforms debugging from a manual, tedious process into a systematic investigation. By reading the full codebase, executing diagnostic commands, forming hypotheses, and implementing verified fixes, Claude Code handles the mechanical aspects of debugging while you provide the domain knowledge and final judgment. The key is providing clear bug reports, asking for hypotheses before fixes, and always insisting on regression tests to prevent the same bug from returning.

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
Anthropic unveiled 10 pre-built finance agent templates on May 5, 2026 across pitchbook building, KYC screening, and month-end close. What each template does and the hours it replaces.
Anthropic shipped finance plugins for Claude Cowork and Claude Code on May 5, 2026. How analysts use them in practice and what the plugin model means for adoption.
Enterprise CIO Guide perspective on Claude Code 2.1 ships background agents, sub-agent spawning, and a hooks API that turn it into a true multi-agent coding platform.
Pair Claude Code with Code-Review-Graph and you have a local-first agentic IDE with deterministic context, blast radius PR review, and zero per-seat indexing fees.
Claude has owned developer mindshare since 3.5 Sonnet. Is the coding edge real? A benchmark and tooling examination of where Claude actually leads in 2026.
Every coding agent has to pick a model. With GPT-5.5 winning Terminal-Bench and Opus 4.7 winning SWE-bench Pro, the agent stack you pick affects which model you get.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI