On this page
  1. The problem: AI wrote it, you don’t understand it, and it’s broken
  2. The four-step debugging system
    1. Step 1: Isolate — narrow the problem to one function
    2. Step 2: Bisect — find which change broke it
    3. Step 3: Instrument — see what’s actually happening
    4. Step 4: Explain — ask the AI to fix the specific bug, not the whole file
  3. The full debugging loop
  4. When the AI can’t fix it
  5. Specific debugging guides
  6. Where AI coding assistants get this wrong in debugging
  7. Checklist
  8. FAQ
    1. What if I don’t understand the code at all?
    2. Should I ask the AI to debug its own code?
    3. What if git bisect points to a commit with 20 changed files?
  9. Related topics
  10. Sources
how-to

How to Debug AI-Generated Code: A Complete System for When You Don't Understand What the AI Wrote

Your AI wrote 300 lines and you don't know what any of it does — and now it's broken. Here's a repeatable debugging system: isolate, bisect, instrument, explain. No prior understanding required.

Quick answer

  • Don’t try to understand the whole file. Narrow to one function that’s broken.
  • The system: isolate the failing unit → bisect to find which change broke it → instrument to see actual values → explain the bug back to the AI to get a targeted fix.
  • This works when you don’t understand the code. It only requires understanding the bug.

The problem: AI wrote it, you don’t understand it, and it’s broken

This is the universal vibecoder debugging experience. The AI generated a 300-line function three days ago. It worked. Now it doesn’t. You don’t know what the function does — the AI seemed to understand it, so you never read it carefully. And now you’re staring at a stack trace in code you didn’t write.

The instinct is to paste the error back into the AI and ask “fix this.” That sometimes works. But when it doesn’t — when the AI produces a different broken version, or fixes one thing and breaks two more — you need a system.

The four-step debugging system

Step 1: Isolate — narrow the problem to one function

You don’t need to understand the whole codebase. You need to find the single function where behavior diverges from expectation.

# Don't try to understand this entire file.
# Find the function that's returning wrong data.

# Good: narrow the problem
# "The function get_user_orders() returns an empty list but the database has 5 orders."

# Bad: try to understand everything
# "This module has 12 functions and one of them is wrong somewhere."

How to isolate:

  1. Follow the stack trace to the call site
  2. Find the last function that was called before the error or wrong output
  3. That’s your target

If there’s no stack trace (wrong output, no error), add print statements at the boundaries between functions to see where the data changes from correct to incorrect.

# Instrument boundaries to find where data goes wrong
print(f"orders before filter: {orders}")  # [1,2,3,4,5]
orders = filter_orders(orders)
print(f"orders after filter: {orders}")   # []  ← problem is in filter_orders

Step 2: Bisect — find which change broke it

If the code worked before and doesn’t now, use git bisect to find the exact commit that introduced the bug. This works even if you don’t understand the code — you only need a yes/no test for whether the bug exists.

# Start bisect
git bisect start

# Mark current commit as bad (bug exists)
git bisect bad HEAD

# Mark a known-good commit (bug didn't exist)
git bisect good <commit-hash-from-when-it-worked>

# Git checks out a commit in the middle. Test it:
# - Run the app, trigger the bug, see if it happens
# - If bug exists: git bisect bad
# - If bug doesn't exist: git bisect good

# Repeat until git identifies the exact commit
git bisect reset  # when done

For a walkthrough with AI-generated code specifically, see the companion guide: How to Find Which AI-Generated Change Broke Your App Using Git Bisect.

Step 3: Instrument — see what’s actually happening

You’ve isolated the function and know which commit broke it. Now instrument the function to see actual values — not what you assume is happening.

def calculate_discount(order_total, user_tier):
    # Instrument entry
    print(f"calculate_discount called: total={order_total}, tier={user_tier}")

    if user_tier == "premium":
        discount = order_total * 0.2
    elif user_tier == "basic":
        discount = order_total * 0.1
    else:
        discount = 0

    # Instrument exit
    print(f"calculate_discount returning: {discount}")
    return discount

Common AI mistakes that instrumentation reveals:

  • Wrong type: the function expects a number but received a string ("100" not 100)
  • Silent None: a function returns None instead of a value, which propagates silently
  • Empty iterable: a filter removes everything because the condition is inverted
  • Wrong default: a dict lookup falls through to the wrong default value

Step 4: Explain — ask the AI to fix the specific bug, not the whole file

Now you know:

  • Which function is broken
  • What input it receives
  • What it actually returns
  • What you expected it to return

Give this to the AI as a targeted prompt:

The function `calculate_discount` in `src/pricing.py` returns 0
when called with order_total=100 and user_tier="basic".

Expected: 10 (10% of 100)
Actual: 0

The bug is likely in this function. Show me the fix without
changing anything else in the file.

This is the opposite of “fix this.” It’s “this specific function, these specific values, what’s wrong?” The AI’s response will be surgical instead of a rewrite.

The full debugging loop

Bug discovered


1. Isolate: find the one function returning wrong data


2. Bisect (if regression): find the commit that broke it


3. Instrument: add prints/debugger at function boundaries


4. Explain to AI: "function X, input Y, expected Z, got W — what's wrong?"


AI produces targeted fix


Apply fix → run tests → verify

    ▼ (still broken)
Loop back to step 3 with new information

When the AI can’t fix it

Sometimes the AI’s fix doesn’t work — or makes things worse. This usually means the bug is architectural (not a single-function error) or context-dependent (the AI doesn’t have enough information). In that case:

  1. Narrow further: split the function into smaller pieces and test each
  2. Compare with a working version: if you have a known-good state (git stash), compare the working vs broken logic
  3. Add more instrumentation: add logging at every branch point (if/else) to see which path is taken
  4. Ask the AI to explain, not fix: “Explain what this function does, step by step.” Understanding the code is often faster than getting the AI to fix it blindly.

Specific debugging guides

This system breaks down into focused techniques depending on what’s broken. Each of these is a standalone guide:

Where this bites vibecoders

The debugging loop above is the difference between a vibecoder who ships and one who stalls. When you don’t understand the code, the natural response is to paste the error back into the AI and hope. That works for simple bugs. For everything else, isolate → bisect → instrument → explain. This turns “I don’t know what’s wrong” into “this function, this input, this expected output — what changed?”

Where AI coding assistants get this wrong in debugging

  • Accepting “fix this” and rewriting 300 lines instead of fixing one function.
  • Not asking for expected vs actual values — it guesses at the bug instead of diagnosing it.
  • “Fixing” the bug by changing behavior elsewhere, creating a cascade of new failures.
  • Producing a fix that works for the specific test case but breaks other inputs.

Checklist

  • Isolate the problem to one function before involving the AI
  • If regression: git bisect to find the exact commit
  • Instrument function boundaries to see actual input/output values
  • Ask the AI: “function X with input Y returns Z, expected W — what’s wrong?”
  • Apply fix → run tests → verify → commit
  • Never accept a multi-function rewrite as a bug fix

FAQ

What if I don’t understand the code at all?

That’s the normal starting point with AI-generated code. Don’t try to understand the whole file — narrow the problem to one function, add print statements or a debugger at its entry and exit, and compare actual vs expected values. Understanding the bug is enough; understanding the whole module can come later.

Should I ask the AI to debug its own code?

Yes, but give it the specific failure: “This function returns [] when I expect [1,2,3]. Here’s the input, the actual output, and the expected output. What’s wrong?” Don’t ask “can you fix this?” — the AI will rewrite the whole file. Pin it to the specific failure.

What if git bisect points to a commit with 20 changed files?

Narrow further. Run git diff <bad-commit>^ <bad-commit> -- <path/to/broken/function> to see only the changes in the file containing the broken function. If that’s still too much, bisect within the commit: comment out sections of the diff until you find the specific change that introduced the bug.


Sources

Share: