Skip to content

AI-Assisted Debugging in Cursor

Bug hunting in Cursor runs in three phases with a different mode for each: Ask mode investigates symptoms and ranks hypotheses, Debug mode instruments the code and collects runtime evidence, and Agent mode applies one targeted fix plus a regression test. The sequence exists to prevent the fix-break-fix loop that guessing produces.

Production returns 500s on 15% of checkout requests. It works flawlessly in development. It started after Tuesday’s deployment, but the diff looks harmless — a small refactor of the payment processing logic — and the error message is the supremely unhelpful “Transaction failed.” Your CEO wants an update every thirty minutes.

The tempting move is to paste the error into Agent mode and say “fix this.” It changes three files, your test case passes, and now a different set of users gets a 403. You tell it to fix that too. Two more files. The original 500 is back, and twenty minutes in you are further from a fix than when you started.

The problem is not Cursor. It is treating debugging as “tell the AI to fix it and hope.” Debugging is a search problem, and AI is very good at searching — as long as you make it search before it edits.

  • A three-phase workflow that uses Ask, Debug, and Agent mode for what each is actually good at
  • A hypothesis-generation prompt that turns symptoms into ranked, testable theories
  • A Debug mode workflow that instruments code, captures runtime data, and finds root causes from evidence
  • A load-test prompt for reproducing an intermittent failure locally
  • Copy-paste prompts for type errors, race conditions, and a cascade of build errors
  • A post-mortem template that documents the bug, the fix, and the prevention

Debugging as a search problem: the three phases

Section titled “Debugging as a search problem: the three phases”

Each phase has a mode, and the mode matters because it constrains what the AI is allowed to do:

  1. Investigate in Ask mode. Read-only. You are building a model of the failure, and nothing should change while you do.
  2. Gather evidence in Debug mode (or with manual logging). Instrumentation only, no behavior changes.
  3. Fix in Agent mode. One targeted change, plus the regression test that proves it.

Skipping straight to phase three is what produces the fix-break-fix loop.

Collect every observable fact first, then ask for theories you can actually test:

Expect it to name things like connection pool exhaustion, a race condition, a timeout misconfiguration, or a missing error handler on one code path. The ranking matters less than the second and third points: a hypothesis you cannot confirm or rule out is a theory that will waste your afternoon.

When you have a stack trace instead of a symptom list, ask for the path rather than the theory:

“Without making any changes” is doing real work in that prompt. It is the difference between a mental model and a surprise diff.

Cursor has a dedicated Debug mode for exactly this. Switch to it with the mode picker, or Cmd+. / Ctrl+. to quick-switch. Unlike Agent mode, it follows a structured investigation:

  1. It explores the relevant files and generates hypotheses
  2. It adds instrumentation (log statements) that report to a local debug server
  3. It asks you to reproduce the bug
  4. It analyzes the collected runtime data
  5. It proposes a targeted fix based on evidence rather than guesswork
The checkout endpoint at POST /api/checkout is returning "Transaction failed"
for ~15% of requests under load. The error happens in the payment processing
step. I can reproduce it locally using a load testing tool (k6 or similar)
that sends 200 concurrent requests.
Find the root cause using instrumentation.

Debug mode adds logs at the points that matter — database connection acquisition, payment API calls, transaction boundaries — and asks you to trigger the bug. With the runtime data in hand it can usually pinpoint the issue in minutes.

When Debug mode is unavailable or you want tighter control, do the same thing by hand. Instrument first:

Then reproduce, and bring back two runs rather than one. The comparison is what makes the diagnosis possible:

Reproducing an intermittent failure on purpose

Section titled “Reproducing an intermittent failure on purpose”

If you cannot trigger the bug by hand, have Agent mode build something that can:

A load test that reproduces the failure is worth more than the diagnosis it produces, because it is also how you verify the fix later.

@logs/debug-output.log @src/payment/processor.ts
Here are the debug logs from the load test. Analyze them and answer:
1. Which requests failed and what do they have in common?
2. What is the timing pattern? Do failures cluster at specific intervals?
3. Is there a resource that's being exhausted (connections, file handles, memory)?
4. Can you identify the exact line where the failure originates?
5. What is the root cause?
Show me the specific code that needs to change and explain why.

A common finding in this scenario: the payment processor acquires a database connection and fails to release it on certain error paths. Under load the pool exhausts, and the subsequent timeout gets wrapped in the generic “Transaction failed” message — which is why the error text never pointed at the real problem.

Switch to Agent mode only now, and constrain it. The template below is the one to keep:

Filled in for the connection leak above, the same shape becomes concrete — note how much of it is about making the next occurrence diagnosable rather than about the leak itself:

Every fix gets a test that would have caught the bug:

Add a regression test for the bug we just fixed.
The test should:
1. Set up the exact conditions that caused the failure (user with [specific condition])
2. Call the endpoint with the same request that was failing
3. Assert that it succeeds with the correct response
4. Also test the edge case where [related condition]
Put the test in @src/routes/__tests__/orders.test.ts following existing patterns.
Run the test to confirm it passes.

If the test fails, the fix was incomplete. If it passes, you have something that stops the bug coming back.

When the bug started after a specific deployment and you have a reliable test, let git do the search:

The checkout load test passes on commit abc123 (Monday) but fails on HEAD (Tuesday).
There are 12 commits between them. Help me set up a git bisect:
1. Create a script that runs the load test and returns exit code 0 if fewer than 1% of
requests fail, exit code 1 otherwise
2. Show me the git bisect commands to find the exact commit that introduced the regression

Twelve commits narrow to one in about four iterations.

TypeScript reports this error at build time:
[PASTE TSC ERROR]
Trace the types involved. Show me:
1. Where the type is defined
2. How it flows through the code to this point
3. Why the types are incompatible
4. The minimal fix that maintains type safety
Do not use `any` or type assertions to fix this. Find the real type issue.
This code has a race condition -- when two requests arrive simultaneously
for the same user, the second request overwrites the first one's data.
Relevant code: @src/services/user-service.ts
Analyze the concurrent execution paths and identify:
1. Which operation is not atomic
2. Where the race window exists
3. The best fix (optimistic locking, database transaction, or mutex)
Show me the fix with before/after code comparison.

With many build errors, fixing them one at a time is the slow path — most of them are downstream of one real problem:

With auto-run enabled, the agent runs the build, reads the errors, fixes them, and iterates until it passes — the loop Steve Sewell at Builder.io popularized.

The step most teams skip, and the one with the longest payoff. Draft it in Ask mode while the session is still in context:

Based on this debugging session, write a post-mortem document covering:
1. Summary: what broke, who was affected, how long it lasted
2. Timeline: when it started, when detected, when fixed
3. Root cause: the connection leak in payment processing
4. Fix: what changed and why
5. Detection gap: why our monitoring didn't catch this sooner
6. Prevention: what we will do to prevent similar bugs (connection pool alerting, code review checklist for resource cleanup)
7. Action items with owners and deadlines
Save to docs/postmortems/2026-02-checkout-connection-leak.md

You are stuck in the fix-break-fix loop. Phase 1 got skipped. Go back to Ask mode, build the model of the system, then make exactly one targeted change.

Instrumentation changes the bug’s behavior. Log statements alter timing enough that a race condition disappears — the Heisenbug problem. Use lighter instrumentation: increment atomic counters instead of logging strings, or take process.hrtime() timestamps that need no I/O.

The AI produces a plausible but wrong root cause. Models pattern-match well and can be confidently wrong. Verify before implementing: if the diagnosis is right, the fix should drive the load test’s error rate to near zero.

The fix papers over the symptom. The classic bad fix is a retry wrapper around the failing operation instead of plugging the leak. Retries mask pool exhaustion briefly and make it worse under sustained load. Push back and ask for the cause.

The agent “fixes” the test instead of the code. Say it outright: “The test is correct. The implementation is wrong. Fix the implementation to make the test pass.”

The instrumentation does not capture the issue. The bug is somewhere else in the call chain than you assumed. Widen the logging, or reproduce several times — intermittent behavior needs more than one sample.

Nothing reproduces locally. Some bugs need production data volumes, real network latency, or specific hardware. Instrument production with structured logging and analyze it in Ask mode, and have the agent search for known issues in the library or service that is failing.

The trace leads into node_modules. Use @Docs to check the library’s issue tracker and changelog, then ask directly: “Has this library been reported to have connection leaks or timeout issues in recent versions?”

There are too many errors to triage. Fix compile errors first because they block everything else, then runtime errors, then logic errors, using the build-cascade prompt above.