Chapter 5

Debugging with AI

Debugging is one of the most time-consuming parts of programming. AI can dramatically accelerate the process — but only if you use it systematically. This chapter teaches you how to turn AI into the best debugging partner you've ever had.


Why AI Excels at Debugging

AI brings specific strengths to debugging that complement — and sometimes surpass — human ability. Understanding these strengths helps you know when and how to leverage AI most effectively.

But there's a critical caveat:

Core Principle

AI assists your debugging — it doesn't replace your analysis. AI can identify what might be wrong and suggest fixes, but only you understand the full context: the business requirements, the intended behavior, and the broader system. The best results come from combining AI's pattern-matching speed with your contextual judgment.


Beginner vs. Senior Debugging Prompts

The gap between how beginners and developers ask AI for debugging help is enormous — and it directly determines the quality of the response.

Beginner Approach

My code doesn't work, fix it

Problems:

  • No code provided
  • No error message
  • No description of expected vs. actual behavior
  • AI must guess everything

Senior Approach

  • Includes the relevant code
  • Includes the exact error message
  • Describes what should happen
  • Describes what actually happens
  • States what was already tried

The Senior Debug Prompt Template

This template works for almost any debugging situation. Copy it, memorize it, make it automatic. The four sections give AI everything it needs for an accurate diagnosis.

Debug Prompt Template
Here is my code:

[paste the relevant function, component, or module]

Error message:
[paste the exact error — including stack trace]

What I'm trying to do:
[describe the intended behavior]

What happens instead:
[describe the actual behavior — error, wrong output, crash, etc.]

What I've already tried:
[list any fixes you've attempted — this prevents AI from
suggesting things you've already ruled out]

Each section serves a specific purpose. The code gives AI the concrete source to analyze. The error message narrows the search space dramatically. The intent vs. reality gap tells AI what kind of bug it is (logic error, runtime crash, wrong output, performance issue). And what you've tried prevents wasted iterations.


The Debugging Workflow

Don't jump straight to AI the moment you see an error. The most effective debugging workflow uses AI at the right moment — after you've done some initial triage yourself.

1
Read the error yourself first — Many errors are self-explanatory once you actually read them. Cannot read properties of undefined tells you something is null that shouldn't be.
2
Identify the area — Use the stack trace to pinpoint which file and line the error originates from. Narrow the scope before involving AI.
3
Give AI focused context — Don't paste your entire app. Paste the relevant function plus the error. Use the template above.
4
Test the suggested fix — Don't blindly apply it. Read the fix, understand why it should work, then test it yourself.
5
Iterate if needed — If the first suggestion doesn't work, tell AI what happened: "I tried your fix but now I get a different error: ..." This gives AI new information to refine its diagnosis.

Pro Tip: Read Errors Before Asking AI

It's tempting to copy-paste every error straight to AI without reading it. Resist this urge. Reading the error yourself first — even if you don't fully understand it — builds your debugging intuition over time. If you always outsource error analysis, you never develop the pattern recognition that makes developers fast. Use AI to augment your debugging skill, not to replace it.


Ask for Analysis, Not Just Fixes

One of the most powerful debugging techniques is asking AI to analyze why a bug occurs rather than just fix it. This approach gives you understanding, not just a patch — and the understanding often reveals deeper issues.

Analyze why this error might occur.
Don't fix it yet — give me the three most likely causes,
ranked by probability.

For each cause, explain:
- Why it would produce this specific error
- How to verify if it's the actual cause
- What the fix would be

This prompt produces a diagnostic analysis, not just a code patch. You learn why the bug exists, which helps you prevent similar bugs in the future. It also avoids the common problem where AI suggests a fix that addresses a symptom but not the root cause.

Debugging Philosophy

Understanding the bug is more valuable than fixing the bug. A fix you don't understand is a future bug waiting to happen. Always ask "why?" before asking "how to fix?"


Log-Based Debugging

When errors aren't clear-cut — when your code runs but produces wrong results — console logs become invaluable. AI is excellent at analyzing log output to trace logic flow.

Here is my function:

const filterActivities = (activities, filters) => {
  const filtered = activities.filter(a => {
    const memberMatch = !filters.members.length ||
      filters.members.includes(a.member);
    const dayMatch = !filters.day || a.day === filters.day;
    return memberMatch && dayMatch;
  });
  return filtered;
};

Here is my console output:

filters: { members: ["Alice"], day: null }
activities count: 12
filtered count: 0   // Expected: 4 activities for Alice

Why is the filter returning zero results when there
should be 4 activities matching "Alice"?

By showing AI the function, the input data, and the unexpected output, you create a precise diagnostic context. AI can often spot the issue immediately — in this case, it might identify that the member field uses full names while the filter uses first names, or that the comparison is case-sensitive.


Stack Traces: Send the Whole Thing

A common mistake is sending only the last line of an error. Always send the complete stack trace. The full trace tells AI exactly how execution reached the failure point — which function called which function, in which file, at which line.

Insufficient

TypeError: Cannot read
properties of undefined

AI knows the symptom but not the location or cause chain.

Complete

TypeError: Cannot read
  properties of undefined
  (reading 'map')
    at ActivityList
      (ActivityList.tsx:23)
    at renderWithHooks
    at mountIndeterminate
      Component

AI knows the exact component, line, and call chain.


Where AI Excels vs. Where You Must Think

Not all bugs are equal in terms of how much AI can help. Understanding this spectrum helps you allocate your time wisely — let AI handle what it's great at, and invest your own thinking where it matters most.

Syntax errors
AI handles easily
Runtime crashes
AI strong
You
Async/await issues
AI strong
You
State / render bugs
AI helps
You verify
API mismatches
AI helps
You verify
Wrong business logic
AI limited
You must think
Architecture problems
AI limited
You must design
Performance issues
AI suggests
You profile & decide

The pattern is clear: AI is strongest with well-defined, pattern-based bugs (syntax, crashes, common framework issues) and weakest with bugs that require understanding business intent, system-wide architecture, or real-world performance characteristics. Your role is to bring that context.


Debugging as Dialogue

The most effective AI debugging sessions are conversations, not single-shot queries. Each exchange gives AI new information, refining its understanding until it reaches the right answer.

Scenario: Debugging a React Re-render Loop
You
My ActivityList component is re-rendering infinitely. Here's the code: [pastes component]. The console shows hundreds of renders. It worked fine before I added the filter feature.
AI
The likely cause is that your useEffect dependency array includes filteredActivities, which is a new array reference on every render because .filter() creates a new array. This creates a loop: render → effect runs → state updates → re-render → new array → effect runs again. Three possible fixes: useMemo for the filtered array, move the filter logic inside the effect, or change the dependency to the filter criteria instead of the filtered result.
You
I tried wrapping with useMemo but the loop continues. Here's the updated code: [pastes code]
AI
I see the issue — the useMemo dependencies include filters, but you're creating a new filters object every render in the parent component. The fix needs to be in the parent: either memoize the filters object or use individual filter values as dependencies instead of the object.
You
That fixed it. But help me understand — why does a new object cause this even if the values inside are the same?
AI
[Explains referential equality vs. structural equality in JavaScript, and how React's dependency comparison uses Object.is()]

Notice how the conversation progressively narrowed the problem. The first response identified the general issue. When the initial fix didn't work, new information led to the real root cause. The developer then asked "why?" — building understanding, not just applying patches.


AI as Preventive Code Reviewer

Don't wait for bugs to appear. One of the most valuable debugging strategies is proactive — asking AI to find potential bugs before they happen.

Review this component for potential bugs.

Look specifically for:
- Null/undefined access without guards
- Race conditions in async operations
- Memory leaks (unsubscribed listeners, uncancelled fetches)
- Edge cases with empty data or missing props
- React-specific issues (stale closures, missing deps)

Don't suggest style improvements — focus only on
correctness and potential runtime failures.

This proactive approach catches bugs at their cheapest point — before they reach users, before they corrupt data, and before you spend an hour debugging them. Run this on every significant component before you consider it done.


Common Mistakes

Debugging Anti-Patterns

🧪 Practical Exercise

Dig up a bug you've encountered recently — or intentionally break something in a project you're working on. Then practice the full debugging workflow:


Key Takeaways

Previous Chapter From Idea to Code
Next Chapter Refactoring and Code Quality