AI-Assisted Debugging in Cursor
PLAI-assisted bug hunting in Cursor is a three-phase loop: the agent investigates the failure without editing code, reproduces it with a failing test or load script to collect runtime evidence, and only then makes one targeted fix in Agent mode. The reproduction doubles as the proof, so the fix is accepted on a red-to-green test, not on a plausible-looking diff.
This page is for developers who debug with Cursor’s agent and for tech leads who decide what evidence a bug-fix pull request must carry. The situation it solves: production returns 500 on about one in seven checkout requests since Tuesday’s deploy, the diff is a small refactor of payment code, and the only error text is Transaction failed. You paste the error into Agent mode and ask it to fix it. It edits three files, a different group of users now gets 403, and twenty minutes later the original 500 is back.
The agent did not fail at coding. It was asked to edit before anyone knew the cause. Debugging is a search problem, and the agent searches well once you stop it from editing during the search.
What you’ll walk away with from this bug-hunting workflow
Section titled “What you’ll walk away with from this bug-hunting workflow”- A mode-per-phase plan that keeps the agent read-only until the root cause is proven
- Eight copy-paste prompts: symptom triage, reproduction, instrumentation, log comparison, the constrained fix, a regression test that must fail first, the build-error cascade, and race-condition diagnosis
- A
git bisect runrecipe for regressions that started with a specific deploy - An evidence checklist a reviewer can approve without reading every line of the fix
- Recovery steps for the six ways AI-assisted debugging goes wrong
Which Cursor mode fits each debugging phase?
Section titled “Which Cursor mode fits each debugging phase?”Each phase limits what the agent may change. The limit, not the model, is what stops the fix-break-fix loop.
| Phase | Goal | Cursor surface | The agent may change | Leave the phase when |
|---|---|---|---|---|
| 1. Investigate | Ranked, testable hypotheses | Plan Mode (or Ask mode) | Nothing | Every hypothesis names the observation that would rule it out |
| 2. Reproduce and gather evidence | A failure you can trigger on demand | Agent mode, restricted to tests, scripts and logging (or Debug mode) | New test files, load scripts, tagged log lines | A test or script fails for the reason you predicted |
| 3. Fix and prove | One cause removed | Agent mode | Only the files the diagnosis names | The reproduction passes, the suite is green, and the debug logging is gone |
Plan Mode “creates detailed implementation plans before writing any code”, which makes it a safe place to think. Before you start, commit or stash your work so that git diff shows only what the agent changes during the hunt. For a rollback point inside one session, see checkpoints and branching.
Phase 1: investigate the bug without touching code
Section titled “Phase 1: investigate the bug without touching code”Turn symptoms into ranked hypotheses
Section titled “Turn symptoms into ranked hypotheses”Write down every observable fact first: the error text, the rate, the environments where it does and does not happen, the start time, and what changed. Then ask for hypotheses you can test, not for a fix.
Expect answers such as connection-pool exhaustion, a race on shared state, a timeout mismatch, or an error path that skips cleanup. Point 3 matters most. A hypothesis that no observation can rule out consumes an afternoon and produces nothing.
Pull production evidence into the session with an MCP server
Section titled “Pull production evidence into the session with an MCP server”When the failure lives in production, give the agent the real events instead of your summary of them. The official Sentry MCP server (getsentry/sentry-mcp, stdio package @sentry/mcp-server 0.42.0, checked with npm view on 26 September 2026) exposes issues, events and traces. Its remote endpoint is https://mcp.sentry.dev/mcp, and Cursor declares a remote server by URL in the project file .cursor/mcp.json:
{ "mcpServers": { "sentry": { "url": "https://mcp.sentry.dev/mcp" } } }The remote server signs you in with OAuth, so no token goes into the file. The first connection opens a browser sign-in, so add the server and sign in before an incident, not in the middle of one. Every loaded server also adds its tool definitions to the agent’s context: reducing MCP token cost shows how to keep that small. Then ask in the same read-only mode: “Find the most frequent unresolved error on the checkout endpoint in the last 24 hours, open its trace, and map each frame to a file in this repository. Do not edit anything.” The before-and-after difference is that the agent reads the stack trace your handler swallowed, instead of guessing from the wrapped message. Other observability servers are compared in observability MCP servers.
Phase 2: reproduce the failure and collect runtime evidence
Section titled “Phase 2: reproduce the failure and collect runtime evidence”Reproduce before you diagnose
Section titled “Reproduce before you diagnose”A reproduction is worth more than a diagnosis, because it is also the test that proves the fix later. For an intermittent failure under load, have Agent mode write the script and nothing else.
Run it with k6 run tests/load/checkout-stress.js. If the failure rate climbs with virtual users, you have a reproduction. If it stays at zero, the difference between your laptop and production (data volume, pool size, network latency) is itself the next hypothesis to test.
For a deterministic bug, the reproduction is a unit or integration test that fails today. The test-driven workflow in Cursor covers writing that test first.
Instrument the path, not the behaviour
Section titled “Instrument the path, not the behaviour”Cursor’s Debug mode is for bugs that need runtime evidence (Cursor’s help, checked 2026-10-12), which is what this step collects, so you can use it here. The manual version below collects runtime evidence in any mode and keeps the instrumentation easy to remove.
Then run the reproduction twice and keep one failing and one passing trace. The comparison is what makes the diagnosis possible.
Point 4 is your acceptance criterion for phase 3. A typical finding for this scenario: processPayment acquires a pooled connection, and the validation-failure branch returns before releasing it. Under load the pool drains, later requests time out waiting for a connection, and the catch block rewraps the timeout as Transaction failed. That rewrap is why the error text never pointed at the cause.
Find the commit that introduced the regression
Section titled “Find the commit that introduced the regression”When the bug started with a specific deploy and you have a reproduction that exits non-zero on failure, let git search the history. The k6 threshold from the load-test prompt already gives you that exit code. The load test needs a fresh app server on every commit, so wrap the steps in a small script, for example tests/load/bisect.sh:
#!/bin/shnpm ci >/dev/null || exit 125 # install this commit's lockfile, not the last one'snpm run build >/dev/null || exit 125 # a commit that does not build is skipped, not blamednode dist/server.js & pid=$! # start the server itself, not an npm wrappertrap 'kill $pid 2>/dev/null' EXIT # stop it however the script endssleep 5 # give the server time to listen on localhost:3000k6 run --quiet tests/load/checkout-stress.jsThen let git drive it:
git bisect start HEAD abc1234 # bad commit first, then the last known good onegit bisect run sh tests/load/bisect.shgit bisect reset # return to where you startedReplace abc1234 with Monday’s deployed commit. Git halves the range on every step, so 12 commits take at most four runs. Exit code 125 tells bisect to skip a commit it cannot test, so a broken build never gets blamed for the regression. Replace dist/server.js with your build’s entry point: killing an npm start wrapper can leave the real server running on port 3000, and the next step then tests the wrong commit. Port 3000 must be free before git bisect run starts and before each step. Keep bisect.sh out of the commits you are testing (an untracked file survives each checkout), and raise the sleep if your server starts slowly.
Phase 3: fix one cause and prove it
Section titled “Phase 3: fix one cause and prove it”Constrain the fix to the diagnosis
Section titled “Constrain the fix to the diagnosis”Switch to Agent mode only now. Cursor starts a fresh context window when you switch modes (Cursor’s help, checked 2026-10-12), so paste the diagnosis in, and the agent works from evidence rather than from its own new theory.
The “no retries” rule is there because a retry wrapper is a common plausible-but-wrong fix: it lowers the error rate for an hour and drains the pool faster under sustained load.
Write a regression test that fails first
Section titled “Write a regression test that fails first”A regression test only proves the fix if it fails on the unfixed code. Ask for that proof explicitly.
If the test passes on the unfixed code, it does not test the bug. Delete it and describe the failing condition more precisely. Keep the test from being edited later to fit the code: protect the oracle explains how.
How do you know the bug fix is right without reading every line?
Section titled “How do you know the bug fix is right without reading every line?”You accept the fix on evidence, not on how the diff reads. Attach this to the pull request:
| Evidence | How you produce it | What it proves |
|---|---|---|
| Regression test red, then green | The stash run above, output pasted into the PR | The test detects this bug and the fix removes it |
| Reproduction before and after | k6 run tests/load/checkout-stress.js on the old and new commit | The failure rate drops to what the phase 2 prediction said |
| Full gates green | Test suite, type check and lint in CI | Nothing else broke |
| Scope matches the diagnosis | git diff --stat lists only the named file and new tests | The agent did not refactor on the side |
| Instrumentation gone | git grep -c CHECKOUT_DEBUG returns nothing | No debug logging ships |
| Independent review | Bugbot or a second agent reviews the PR against the diagnosis | A reviewer that did not write the fix looked for side effects |
Sign-off: the developer who ran the hunt owns the evidence. The reviewer, typically the tech lead for an incident fix, approves when every row is present, and reads the diff only where a row is missing or surprising. After the deploy, watch the same error in your monitoring for one traffic peak before you close the incident. The monitoring guide covers that alert. The wider practice is described in reading evidence instead of code.
How do you debug build-error cascades and race conditions in Cursor?
Section titled “How do you debug build-error cascades and race conditions in Cursor?”Two recurring bug shapes need their own recipe: a wall of compiler errors with a few hidden causes, and a lost update that only appears under concurrency.
A cascade of build or type errors
Section titled “A cascade of build or type errors”Forty errors after a dependency bump usually have two or three causes. Fixing them in file order is the slow path.
How do you debug a race condition with the agent?
Section titled “How do you debug a race condition with the agent?”Logging can change timing enough to hide a race. If the bug disappears once instrumented, record timestamps into an in-memory array with process.hrtime.bigint() and print them after the run, so the hot path does no I/O.
How do you write the post-mortem for an AI-assisted fix?
Section titled “How do you write the post-mortem for an AI-assisted fix?”Ask the agent, in Plan Mode or Ask mode, for a post-mortem with summary, timeline, root cause, fix, detection gap, prevention and action items, saved to docs/postmortems/. Switching modes starts a fresh context window (Cursor’s help, checked 2026-10-12), so attach the diagnosis notes and the fix commits with @ instead of relying on the earlier session. The detection gap (“why did our monitoring show Transaction failed instead of the timeout?”) usually produces the most valuable action item. Check the timeline against your incident log before you publish it: the agent knows only what you attached.
Which recurring bugs deserve a saved prompt?
Section titled “Which recurring bugs deserve a saved prompt?”Save prompts you reuse as a Rule or an Agent Skill so the whole team gets them. The Rules guide shows the format. For a ready-made method, the systematic-debugging skill from obra/superpowers is written for use “when encountering any bug, test failure, or unexpected behavior, before proposing fixes”, and walks the agent through root-cause investigation, pattern analysis and hypothesis testing before implementation. Install it for Cursor with the skills CLI (1.7.0, checked 26 September 2026):
npx skills add obra/superpowers --skill systematic-debugging -a cursorRead the skill’s SKILL.md before you install it: open issue #2277 (10 September 2026) reports that its directory ships pressure-test fixtures that get copied into the runtime folder. More options are compared in testing and debugging skills.
When AI-assisted debugging in Cursor goes wrong
Section titled “When AI-assisted debugging in Cursor goes wrong”The fix-break-fix loop. The agent edits, something else breaks, and it edits again. Recovery: git stash or restore the last clean commit, return to Plan Mode, and do not leave phase 1 until each hypothesis has a falsifying observation.
A confident but wrong root cause. The explanation reads well and the fix changes nothing. Recovery: the phase 2 prediction exposes it. If the load test does not move the way the diagnosis predicted, the diagnosis is wrong, however convincing it sounded. Go back to the trace comparison with the new data.
The fix hides the symptom. Retries, a larger pool or a longer timeout make the error rarer without removing its cause. Recovery: reject the diff and restate the rule “fix the cause named in the diagnosis; no retries, pool or timeout changes”.
The agent edits the test instead of the code. The regression test suddenly passes because its assertion changed. Recovery: say “The test is correct. The implementation is wrong. Do not modify tests/payment/connection-leak.test.ts.” Then check git diff --stat for test-file changes before you accept anything.
The instrumentation misses the failure. The logs show nothing different between the failing and passing runs. Recovery: the bug is elsewhere in the call chain. Widen the logging one layer out (middleware, the database driver, the HTTP client) and collect several failing samples, because one intermittent sample can mislead.
Nothing reproduces locally. Some failures need production data volumes, real latency or specific infrastructure. Recovery: add structured, tagged logging behind a flag, deploy it, analyse the production output in Plan Mode or Ask mode, and ask the agent to check the failing library’s changelog and issue tracker for known leaks or timeouts in your version.