In plain English
Debugging with an AI coding agent means using a tool like Claude Code or Cursor to help you find and fix a bug — not just to write code. The agent can read your files, run commands, see test output, and propose edits. Used well, it is a fast, tireless pair-debugger. Used badly, it is a confident guessing machine that makes the symptom disappear without ever fixing the cause.

Here is the trap most beginners fall into. You hit an error, copy the stack trace, paste it into the agent, and say "fix this." The agent reads the trace, pattern-matches it against a thousand similar ones it saw in training, and edits some code. Sometimes the error goes away. Often it goes away for the wrong reason — the agent wrapped the failing line in a try/except, or added a null check that hides the real problem one layer deeper. The bug is still there; you just can't see it anymore.
Think of a good human debugger versus a panicked one. The panicked junior changes three things at once, the test passes, and they ship it — with no idea which change worked or whether they broke something else. The senior does the boring thing: reproduce the bug reliably, narrow down where it lives, form a single clear theory about why, prove that theory with a test, then fix it and watch the test flip from red to green. An AI agent can do either. Your job is to force it into the senior's loop.
Why it matters
Writing new code with an agent is forgiving: if the output is wrong, you usually notice quickly because nothing works yet. Debugging is different. You already have a working system with one broken part, and a careless fix can quietly break other parts while making the original symptom vanish. That is why a sloppy AI debugging session is more dangerous than a sloppy AI feature.
Three real problems make the disciplined loop worth learning:
- The agent guesses confidently. A language model is trained to produce a fluent, plausible answer, not to say "I'm not sure yet." Ask it why a bug happens and it will give you a crisp, authoritative theory — which may be completely wrong. Without a reproduction and a test, you have no way to tell a correct diagnosis from a confident hallucination.
- Symptom-hiding fixes pass review. Silencing an exception, catching-and-ignoring, or loosening a type all make the error message disappear. The code compiles, the obvious test passes, the diff looks small. Then the same bug resurfaces in production as corrupted data or a silent wrong answer — far harder to trace than the original crash.
- Scope creep. Given a vague "make it work," an agent may reformat a file, rename variables, or 'improve' unrelated functions in the same edit. Now your bug-fix diff touches forty lines across five files, and you can't tell which change actually mattered or what new risk you just introduced.
The payoff of doing it properly is leverage. Once you can reliably reproduce a bug and describe it precisely, an agent is genuinely excellent at the tedious middle: adding logging, bisecting which commit introduced the problem, reading an unfamiliar library's source to understand a stack trace, or writing the failing test you'd have written by hand. You stay in charge of what counts as fixed; the agent does the typing.
How it works: the debugging loop
A disciplined agent-assisted debug runs as a loop of five steps. The order matters: each step gives the agent the information it needs to not guess in the next one. Skip a step and you are back to pasting a trace and hoping.
1. Reproduce
A bug you can't reproduce, you can't fix — and an agent can't either. Before anything else, get a single command or short sequence that triggers the bug every time. Give the agent the exact steps, the full error output (not a screenshot, the text), the relevant environment, and the input that breaks it. Ask it to confirm it can reproduce before proposing any change. If the failure is intermittent, that is the first thing to investigate — flaky reproduction usually means timing, state, or randomness.
2. Isolate
Now shrink the search space. Where, roughly, does the bug live? This is where agents shine: ask it to add temporary logging around the suspect path, to run a git bisect to find the commit that introduced the regression, or to comment out half the pipeline and see if the symptom survives. The goal is to go from "something in this 5,000-line app is wrong" to "the value is already wrong by the time it reaches this one function."
3. Hypothesize — out loud, before editing
This is the single most important step and the one beginners skip. Before the agent changes any code, make it state the cause in plain words: "the bug is X because Y; if I'm right, then Z should be true." A hypothesis is checkable; a fix is not. Forcing this step catches the agent's confident-but-wrong theories early, because you (or a quick test) can falsify a claim before any code moves.
4. Write a failing test
Turn the hypothesis into a test that fails right now for the right reason. A red test is proof you've actually captured the bug, not just a symptom. It also pins the bug down so it can't silently come back later. Have the agent write the test, then run it and confirm it fails — and read why it fails, to be sure it's failing on the real defect and not a typo in the test.
5. Fix and verify
Only now do you fix. The change should make the new test go from red to green while every existing test stays green. Keep the diff small and scoped to the cause — if the agent's fix touches unrelated files, push back. "Red → green, nothing else broke" is the definition of done.
A worked example
Suppose a function that totals a shopping cart sometimes returns the wrong number. Here is the difference between the lazy prompt and the disciplined one.
The lazy way. You paste the error and say "the cart total is wrong, fix it." The agent adds round() around the result. The reported number now looks right on your one test case — and the underlying float-precision or off-by-one bug is still there, just rounded into hiding.
The disciplined way. You drive the loop. A prompt like this keeps the agent honest:
The cart total is sometimes wrong. Reproduce it first:
run `pytest tests/cart_test.py -k total` and show me the output.
Then, BEFORE changing any code:
1. State your hypothesis for the cause in one or two sentences.
2. Write a NEW test that fails because of this bug. Run it; show me
it fails, and confirm it fails for the reason you described.
Wait for me to approve the hypothesis. Do NOT edit application code yet.
Do NOT wrap anything in try/except or round() to make the number look
right. We want the cause, not a hidden symptom.Now the agent reproduces, proposes (say) "discounts are applied per-item as floats and summed, so rounding error accumulates," and writes a failing test that adds three discounted items and checks the exact total. You approve. Then it fixes the cause — compute in integer cents — and both the new test and the existing suite pass. You can see exactly why it was broken and exactly why it now isn't.
Anti-patterns to watch for
These are the moves an agent makes when it is optimizing for "make the error go away" instead of "fix the bug." Learn to spot them in a diff, because they all look harmless at a glance.
| Anti-pattern | What it looks like | Why it's bad | What to ask instead |
|---|---|---|---|
| Symptom silencing | Wraps the failing line in try/except that swallows the error, or adds a bare null check | The crash is gone but the wrong data flows on; the bug resurfaces later, quieter and harder to trace | "Why is the value wrong here in the first place? Fix the cause, don't catch the symptom." |
| Scope creep | The fix also reformats the file, renames things, or 'improves' unrelated functions | You can't tell which change fixed the bug or what new risk you added; review becomes guesswork | "Change only what's needed for this bug. Keep the diff minimal and scoped." |
| Test deletion / weakening | Edits or deletes the assertion that was failing so the suite goes green | It makes the bug officially not-a-bug; you lose the proof and the regression guard | "Never change a test to pass. If a test is wrong, explain why before touching it." |
| Confident wrong theory | States a crisp cause and edits immediately, no evidence | You ship a plausible-sounding fix for a bug you never actually located | "Prove it with a failing test before you change code." |
| Magic constant tweak | Nudges a timeout, retry count, or threshold until the flaky test passes | Hides a real race condition or ordering bug behind luck | "Is this masking a timing bug? Find what we're actually racing against." |
Practical tips for sharper sessions
- Give it eyes, not just the error. Paste the full stack trace and the surrounding code, recent logs, and the input that triggers the bug. The more context the agent can read directly, the less it has to invent. Agents that can run your test command themselves beat ones that only see what you paste.
- Change one thing at a time. Insist on small, single-cause diffs. If a fix needs three changes, that is three commits, each verified — not one big leap of faith.
- Use logging as a conversation. Ask the agent to add temporary
print/log lines, run the repro, then read the output together before editing. Watching the actual values flow is how a real diagnosis happens — for the agent and for you. - Keep the agent on a leash for risky edits. Review before applying, especially on shared code. See coding-agent permissions for setting what an agent may run or change without asking.
- Commit the failing test first. Land the red test as its own commit, then the fix. Now
git logtells the story: here is the bug, captured; here is the fix that turned it green. - When it spirals, reset. If the agent has made three guesses and the bug is still there, stop. Clear the context, re-state the reproduction from scratch, and force the hypothesis step. A fresh, well-framed start beats a long thread full of failed attempts.
Most of this is just good debugging — the same loop you'd run alone. The agent doesn't change the method; it makes each step faster, if you keep it inside the method. For the prompting side of all this, see how to prompt coding agents.
Going deeper
Once the basic loop is second nature, a few advanced patterns make agent-assisted debugging genuinely powerful — and a few edge cases keep you honest.
Bisecting with an agent. For a regression — "it worked last week" — git bisect is unbeatable, and it pairs perfectly with an agent. Give it a script that returns pass/fail for the bug, and it can drive the bisect to the exact commit that introduced it, then read that commit's diff and explain what changed. You go from "somewhere in 200 commits" to "this one line" in minutes.
Heisenbugs and concurrency. Some bugs only appear under load, timing, or specific ordering. Agents are weakest here, because the bug doesn't reproduce on demand and there is no clean trace to read. The move is to make it deterministic first: pin the seed, force the thread order, or build a stress test that fails reliably. Don't let the agent paper over a race with a longer timeout — that is the magic-constant anti-pattern wearing a disguise.
Debugging across a boundary. When the bug spans your code and a third-party library or API, an agent's ability to read the library's source (or its docs) is a real edge — it can trace a stack trace into code you've never opened. Still, verify what it claims the library does against the official docs; a model's memory of a specific function's behavior can be outdated or wrong.
The trust calibration. The honest open problem is that an agent will always give you a confident answer, so you must supply the skepticism. The failing-test step is your skepticism made mechanical: it forces a falsifiable claim into the loop where a model would otherwise just assert. Treat every retrieved or recalled fact as a claim to verify, every fix as a hypothesis until a test confirms it. That habit — never letting confidence substitute for evidence — is what separates debugging with an agent from being debugged by one. For catching issues before they become bugs, pair this with AI code review and a spec-driven workflow.
FAQ
Why does my AI agent keep guessing the wrong fix?
Because you're asking it to fix before it has located the bug. A language model will always produce a confident, plausible-sounding fix even when it doesn't actually know the cause. Force it to reproduce the bug, state a hypothesis, and write a failing test before editing any code — a test gives you a way to tell a correct diagnosis from a confident guess.
How do I stop the agent from hiding errors instead of fixing them?
Tell it explicitly not to silence symptoms: no wrapping failing lines in try/except, no round() or null checks just to make the error disappear, no weakening tests to pass. Ask "why is the value wrong in the first place?" and require a fix that targets the cause. If the error vanishes but you don't understand the mechanism, treat the bug as unfixed.
What's a good debugging prompt for an AI coding agent?
Structure it as the loop: "Reproduce this first and show me the output. Then, before editing any code, state your hypothesis for the cause and write a new test that fails because of this bug. Wait for my approval. Don't silence the symptom — we want the cause." The key phrase is state your hypothesis before editing, which turns the agent from a fix-emitter into a diagnostician.
Should I let the agent change code before I approve a diagnosis?
No. Approve the hypothesis and the failing test first. If the agent edits application code before you've confirmed why the bug happens, you lose the ability to tell whether the fix addressed the real cause or just made the symptom disappear. Keep risky edits behind a review step — see coding-agent permissions for how to gate what an agent may change automatically.
Why does the agent's fix make the test pass but break something else?
Usually scope creep: the agent changed more than the bug required, or fixed a symptom in a way that shifts the problem elsewhere. Insist on minimal, single-cause diffs and always run the full test suite after a fix, not just the one new test. "Red → green, and nothing else broke" is the real definition of done.
Can an AI agent debug bugs that only happen sometimes?
Intermittent bugs (races, timing, ordering, randomness) are where agents are weakest, because there's no reliable reproduction or clean trace to read. Make the failure deterministic first — pin random seeds, force thread ordering, or build a stress test that fails reliably — then run the normal loop. Don't accept a longer timeout or more retries as a 'fix'; that hides the race rather than solving it.