Debugging is where Windsurf's Cascade agent earns its keep: it can read your @terminal output, reason over your @git diffs, search the whole repo with @codebase, edit files, and then run the tests and read the results to confirm the failure is gone. The 22 prompts below are complete and copy-paste — drop them into the Cascade pane, swap the [bracketed] placeholders, and let the agent do the tracing. Every prompt insists on the real cause, defines acceptance criteria, and keeps Cascade from quietly masking the symptom.

These are debugging-specific. For broader technique see the 40 Best Windsurf AI Prompts roundup and the how-to-prompt-Windsurf guide; for cleanup after the fire's out, the refactoring prompts are the companion set.

Advertisement

Reproduce & isolate

You can't fix what you can't trigger reliably. These prompts get Cascade to build a minimal repro, add throwaway logging you can interpret, and narrow the failure to a single recent change before anyone writes a fix.

1. Write a minimal reproduction

Chat mode. I have this bug: [describe the symptom, e.g. "cart total shows NaN when a coupon is applied"].
Using @codebase, find the code paths involved and write the SMALLEST standalone reproduction that triggers it — a single script or a single failing test in [test dir], with no unrelated setup.
List every input/state that must be true for the bug to appear. Do not fix anything yet — I just want a reliable repro I can run with [npm test / node repro.js].

Why it works: a minimal repro removes noise and gives you a fast pass/fail signal for the fix later.

2. Add temporary logging, then interpret it

Write mode. In @file:[path/to/module] I don't know where [value/state] goes wrong.
Add clearly-marked temporary console logging (prefix each line with "DEBUG-[ticket]") at the key branch points and around [the suspicious function]. Don't change any logic.
Then tell me: run [command] and paste the output back to you with @terminal — read it and pinpoint the exact line where [value] first becomes wrong. After we find it, you'll remove every DEBUG-[ticket] line.

Best for: bugs with no stack trace, where you need to watch state evolve.

3. Bisect the breaking change with @git

Chat mode. This worked on [last known good ref/tag] and is broken on [current branch]: [symptom].
Read @git — the recent commits and diffs between those points. Identify the SMALLEST change most likely to have caused this and explain the exact mechanism (what the old code guaranteed that the new code doesn't).
Rank your top 3 suspect commits with a confidence and a one-line reason each. Don't edit anything — I'll confirm the culprit first.

Why it works: narrows a regression to a diff instead of the whole file, so the fix is surgical.

Read the error

Hand Cascade the exact error text — via @terminal or pasted between backticks — and ask for the root cause plus the fix, not a paraphrase. This section covers stack traces, cryptic messages, TypeScript errors, and build failures.

4. Root-cause a stack trace from @terminal

Read @terminal — the most recent run of [command] crashed with a stack trace.
Trace it to the FIRST line in my own code (ignore node_modules frames) and explain the actual root cause, not just the throwing line. Then propose the minimal fix.
Show me the fix as a diff and wait for my OK before editing. Acceptance: after the fix, re-run [command] and the crash is gone with no new errors.

Best for: uncaught exceptions where the top frame is a symptom, not the cause.

5. Explain a cryptic error message

Explain this error in plain terms, then fix it in my code:
```
[paste the exact error, e.g. "TypeError: Cannot read properties of undefined (reading 'map')"]
```
Using @codebase, find where in [feature/file] this originates. Tell me (1) what the error literally means, (2) why it's happening HERE given my data flow, (3) the smallest correct fix. Don't just add optional chaining to silence it — fix why the value is undefined.

Why it works: forces an explanation of why here, which surfaces the real defect.

6. Fix a TypeScript type error

Write mode. @terminal shows this TypeScript error after `tsc --noEmit`:
[reference @terminal or paste the TSxxxx error and file:line]
Fix it PROPERLY — correct the underlying types in @file:[path], don't reach for `any`, `as`, or `@ts-ignore` unless you justify why no better option exists.
Then run `tsc --noEmit` again and confirm zero errors. Don't change runtime behavior; if the types reveal a real bug, flag it before fixing.

Best for: type errors that are actually pointing at a genuine logic mismatch.

7. Fix a failing build or compile error

My build is broken. Read @terminal — the output of [npm run build / your build command].
Find the root cause (missing import, bad path, version mismatch, misconfigured [bundler/config]) and fix it with the smallest change. If it's a config issue, edit @file:[config file] and explain the one line that mattered.
Acceptance: [build command] exits 0 with no warnings introduced. Re-run it yourself and paste the result.

Why it works: Cascade runs the build itself and iterates until it's actually green.

Trace across the codebase

When the bug lives between files, point Cascade at the whole repo with @codebase and make it follow the data. These prompts track where a value is set, how a request flows through layers, and where a null or race first appears.

8. Find where a value is set or mutated

Chat mode. Using @codebase, find EVERY place [variable/field, e.g. `user.role`] is assigned or mutated across the repo — reads and writes.
For each, give file:line and a one-line note on what it does. Then tell me which of these could set it to [the wrong value I'm seeing] at [when the bug happens].
Don't change code — I want the full map first.

Best for: "how did this field become X?" bugs with many writers.

9. Follow a request through every layer

Chat mode. Trace the full path of a [POST /api/orders] request through @codebase: route → controller/handler → service → data layer → response.
At each hop, note what transforms [the field that's wrong]. Point to the exact function where it's set incorrectly for input [example payload]. Give me the chain as a numbered list with file:line, no edits yet.

Why it works: layered apps hide the mutation; a full trace exposes the one hop that lies.

10. Trace the source of an undefined or null

[value/prop, e.g. `session.user`] is undefined at @file:[path]:[line] when [scenario].
Using @codebase, work BACKWARD from that line to find the origin: where should it have been populated, and why isn't it on this path? Distinguish "never set" from "set then overwritten/cleared".
Give me the root cause and the fix location. Fix the source, not the crash site.

Best for: null/undefined errors where the crash is far from the cause.

11. Diagnose a race condition or async bug

Chat mode. This is intermittent: [symptom, e.g. "stale data ~1 in 20 loads"]. I suspect an async/race issue in @file:[path].
Read the async flow (awaits, promises, effects, event handlers, shared state) and identify any ordering assumption that isn't guaranteed — unawaited promises, state read before it's set, two paths writing the same value.
Explain the exact interleaving that produces the bug, then propose a fix that makes ordering deterministic. No edits until I confirm the interleaving is right.

Why it works: naming the bad interleaving is the whole fight; the fix is usually small once it's named.

Advertisement

Framework & runtime bugs

Framework-specific failures have their own smell. These prompts target React re-renders and state, hydration mismatches, API 500s read from server logs, and CI failures reconstructed from the CI log.

12. Fix a React re-render / state bug

Write mode. In @file:[Component.tsx], [symptom, e.g. "the list re-renders on every keystroke and loses focus" / "state updates one render late"].
Diagnose the real cause — stale closure, missing/incorrect dependency array, state derived from props, an object/array recreated each render, or setting state in render. Explain which one it is.
Fix it correctly (don't just wrap everything in useMemo). Keep behavior identical otherwise. Then confirm with @terminal that the component's tests still pass.

Best for: re-render loops, lost input focus, and off-by-one state.

13. Fix a hydration mismatch

@terminal shows a hydration mismatch warning on [route/page] in [Next.js / your SSR framework]:
[reference @terminal or paste the warning]
Find what renders differently on server vs. client in @file:[page/component] — Date/random values, `window`/`localStorage` reads during render, browser-only branches, or invalid nested HTML. Explain the specific mismatch.
Fix it so server and client output match, without disabling SSR for the whole page. Confirm the warning is gone.

Why it works: hydration bugs are always a server/client divergence — naming the divergence is the fix.

14. Fix an API 500 with server logs

My [GET /api/report] returns 500. Read @terminal — the server logs from the failing request.
Trace the logged stack/error to the handler in @codebase, find the root cause (bad query, unhandled null, missing await, wrong env var), and fix it. Return a proper error response for the genuinely-invalid case instead of a 500.
Acceptance: reproduce with [curl command or steps], get a 200 (or a correct 4xx) — verify it yourself before telling me it's done.

Best for: backend 500s where the log holds the real error.

15. Fix a failing CI test from the CI log

This test passes locally but fails in CI. Here's the CI log:
```
[paste the failing CI job output — test name, assertion, error]
```
Figure out why it fails ONLY in CI: environment differences (timezone, locale, env vars), test order/shared state, a race under load, or an unmocked network/time dependency. Using @codebase, locate the flaky test and its subject.
Fix the real cause so it's deterministic in CI — do not just add retries or increase the timeout unless that's genuinely correct. Explain the difference that mattered.

Why it works: "passes locally, fails in CI" is almost always environment or ordering — the prompt aims Cascade straight at those.

Systematic fixing

The difference between a guess and a diagnosis is method. Make Cascade rank hypotheses, verify the top one before touching code, add a regression test, and refuse to paper over the symptom.

16. Rank hypotheses, verify the top one, then fix

Bug: [symptom + how to reproduce]. Work systematically.
1) Using @codebase, propose the 2-3 most likely root causes, ranked, each with a confidence and how you'd confirm it.
2) Verify the top hypothesis by reading the relevant code (and add one temporary log or a quick check if needed) — tell me whether it's confirmed or ruled out.
3) Only once confirmed, apply the minimal fix and run [test command] to prove it. If the top hypothesis is wrong, move to the next before editing.

Best for: your default debugging loop — diagnosis before edits.

17. Add a regression test after the fix

Write mode. We just fixed [bug] in @file:[path]. Now lock it in.
Write a regression test in [test file] that fails on the OLD behavior and passes on the fixed code. Name it so the ticket [ID] is obvious. Cover the exact input that triggered the bug plus one nearby edge case.
Run the full suite with @terminal and confirm the new test passes and nothing else broke.

Why it works: a test that reproduces the bug guarantees it can't silently return.

18. Don't mask the error — find the real cause

Diagnose [symptom] in @file:[path]. Hard rule: DO NOT mask it.
No try/catch that swallows, no `?.` or `?? default` to dodge a null, no disabling the failing assertion, no widening a type to `any`. Find WHY the bad value/state occurs and fix that.
Before editing, state the root cause in one sentence. If a defensive guard is genuinely correct, justify why it's the right fix and not a cover-up.

Best for: pairing with any fix prompt when you don't trust the shortcut.

Performance & memory

Slow and leaky counts as broken. These get Cascade to hunt a memory leak by finding what's retained, and to profile a slow endpoint or query and fix the actual bottleneck.

19. Find and fix a memory leak

Chat mode. Memory grows over time in [service/component] and doesn't come back down [under load / after navigation].
Using @codebase, hunt for common leak sources: listeners/subscriptions/timers never removed, caches/maps that only grow, closures holding large objects, [React effects without cleanup / connections never closed].
List each suspect with file:line and why it retains memory, ranked by likelihood. Then, in Write mode, fix the top suspect (add the missing cleanup) and tell me exactly what to measure to confirm the leak is gone.

Why it works: leaks are almost always a missing cleanup; the prompt enumerates the usual suspects.

20. Profile and fix a slow endpoint or query

[GET /api/dashboard] takes [~Xs]. Find and fix the bottleneck.
Read the handler via @codebase and identify the real cost: N+1 queries, a missing index, an unbounded loop, unnecessary serialization, or a blocking call in a hot path. Point to the exact lines.
Fix the biggest offender with the smallest correct change (batch the query / add the index / cache appropriately), keep results identical, and tell me how to measure the before/after. Don't micro-optimize things that don't dominate the time.

Best for: a slow route where an N+1 or missing index is quietly the whole cost.

21. Diff working vs. broken environment

Chat mode. It works in [dev/staging] but fails in [prod/other machine]: [symptom].
Compare the two environments systematically — env vars, config files, dependency versions (@file:[lockfile]), Node/runtime version, build flags, and feature toggles. Using @codebase, find every place code branches on environment.
List the differences most likely to explain the symptom, ranked, and tell me exactly what to check to confirm. No edits until we've isolated the difference.

Why it works: "works here, not there" is a config/version delta — the prompt turns it into a checklist.

22. Turn the fix into a durable debugging rule

We keep hitting [class of bug, e.g. "unawaited promises causing stale reads"]. Create a rule so Cascade catches it automatically.
Write a scoped rule file at .windsurf/rules/debugging.md with a Glob trigger for [**/*.ts] that says: when editing or reviewing async code, flag unawaited promises and state read before it's set; when fixing a bug, never mask it — find the root cause and add a regression test.
Keep it under 15 lines. After you write it, summarize the trigger and scope so I can confirm it won't over-fire.

Best for: stopping a recurring bug class at the source; pairs with the refactoring prompts for ongoing code health.

That's the debugging kit. Keep the diagnosis prompts in Chat mode, switch to Write mode for the fix, and always end on a green test run. When you're ready to go beyond bug-fixing, the best Windsurf prompts roundup and the prompting guide cover planning, building, and reviewing with Cascade end to end.

Frequently Asked Questions

Should I debug in Cascade Write mode or Chat mode?

Use Chat/Ask mode to diagnose without touching files — it can read a stack trace, propose hypotheses, and explain the root cause read-only. Switch to Write mode once you agree on the fix so Cascade can edit files and run the tests to confirm the failure is gone.

How do I give Cascade a stack trace or terminal error?

Type @terminal to pull your most recent terminal output — build errors, test failures, stack traces — straight into the prompt, or paste the trace inline between triple backticks. @terminal is more reliable because it captures the exact output without copy/paste truncation.

Can Windsurf find which recent change caused a bug?

Yes. Reference @git so Cascade can read your recent diffs and commit history, then ask it to bisect — identify the smallest recent change that could produce the symptom and explain the mechanism. It reasons over the diff rather than running an actual git bisect unless you ask it to.

How do I stop Cascade from masking the error instead of fixing it?

State it explicitly: "Find the real cause — do not add try/catch, optional chaining, or default values to hide the symptom." Add acceptance criteria that require the failing test to pass and demand a one-line explanation of the underlying bug before any edit.

How do I make sure a bug does not come back?

After the fix, ask Cascade to add a regression test that fails on the old code and passes on the new code, then run the whole suite. A prompt like "write a test that reproduces this bug, confirm it fails on main, apply the fix, confirm it passes" locks the behavior in.

Which model is best for debugging in Windsurf?

Any of the strong reasoning models — Claude Opus 4.8, Sonnet 5, or GPT-5.x — handle root-cause analysis well. For a tricky multi-file race condition or memory leak, pick a high-reasoning model, but a precise prompt with the right @-mentions matters more than the model choice.

Advertisement