Debugging with Cursor
Learning Outcomes
- Use Cursor's AI to explain error messages in plain language
- Apply fix-in-place for quick error resolution via the lightbulb menu
- Interpret terminal errors with AI assistance
- Iterate on bug fixes using Chat conversations
- Combine the built-in debugger with AI for complex issues
Lesson Plan
| Segment | Duration | Topic |
|---|---|---|
| Intro | 3 min | Why AI changes the debugging workflow |
| Demo 1 | 8 min | Explaining errors — red squiggles and error panels |
| Demo 2 | 8 min | Fix-in-place with the lightbulb quick fix |
| Demo 3 | 8 min | Terminal errors — interpreting stack traces |
| Explain | 5 min | Iterating on fixes with Chat |
| Demo 4 | 8 min | Debugger + AI — breakpoints meet conversation |
| Wrap-up | 5 min | Common workflows and key takeaways |
Before You Begin
Pre-work:
- Complete Lesson 4 — Multi-File Context
- Have a project with some code that produces errors (or intentionally introduce one)
- Familiarise yourself with Cursor's built-in terminal (Ctrl+` to open)
Shopping List:
- A project with at least one file containing a bug or error
- Cursor open with the terminal panel visible
- The Problems panel accessible (View → Problems, or Cmd+Shift+M / Ctrl+Shift+M)
Error messages — especially stack traces and cryptic compiler errors — are one of the most common places developers get stuck. Cursor's AI excels at translating these into plain language.
Method 1: Select the error and ask Chat
- When you see a red squiggly underline in your code, hover over it to see the error tooltip
- Select the line with the error
- Press Cmd+L (Mac) / Ctrl+L (Windows) to open Chat with the selection attached
- Ask: "What does this error mean and how do I fix it?"
Method 2: Copy a terminal error into Chat
- Run your code and see an error in the terminal
- Select the error output (stack trace and message)
- Press Cmd+L / Ctrl+L
- Ask: "Explain this error and suggest a fix"
Method 3: Use the Problems panel
- Open Problems panel with Cmd+Shift+M
- Click on an error to navigate to it
- With your cursor on the error line, press Cmd+L
- Ask the AI about it
- Open Problems panel with Ctrl+Shift+M
- Click on an error to navigate to it
- With your cursor on the error line, press Ctrl+L
- Ask the AI about it
What the AI provides:
- Plain-language explanation of what the error means
- The likely cause in your specific code
- A suggested fix (often with code you can apply directly)
- Context about why this error occurs in general
Example interaction:
You: [selected: TypeError: Cannot read properties of undefined (reading 'map')]
What's causing this error?
AI: This error means you're calling .map() on a variable that is undefined.
Looking at line 24, you're calling `users.map(...)` but `users` hasn't been
assigned a value yet when this code runs.
This commonly happens when:
1. An async fetch hasn't completed before render
2. The initial state is undefined instead of an empty array
Fix: Change your state initialisation from:
const [users, setUsers] = useState()
to:
const [users, setUsers] = useState([])
Cursor enhances the standard VS Code lightbulb (Quick Fix) with AI-powered fix suggestions.
How to trigger the AI fix:
- Place your cursor on a line with an error (red squiggly underline)
- A lightbulb icon appears in the left gutter (or hover until you see it)
- Click the lightbulb or press Cmd+. (Mac) / Ctrl+. (Windows)
- Look for AI-powered fix options — they're marked differently from standard Quick Fixes
What you'll see in the Quick Fix menu:
- Standard IDE fixes (auto-import, add missing semicolons) — these are deterministic
- AI Fix — Cursor's AI-generated fix suggestion — this appears as a distinct option, often labelled "Fix with AI" or similar
The AI Fix workflow:
- Click the AI Fix option
- Cursor generates a proposed change (shown as a diff)
- Review the green/red diff highlighting
- Accept (Tab) or reject (Escape)
When lightbulb AI fixes work best:
| Error Type | AI Fix Effectiveness |
|---|---|
| Type errors (wrong type assigned) | Excellent — usually one-line fix |
| Missing imports | Excellent — finds the right module |
| Null/undefined errors | Good — adds null checks |
| Syntax errors | Good — fixes typos and structure |
| Logic errors | Moderate — may need iteration |
| Complex runtime bugs | Poor — use Chat instead |
Example: fixing a type error
// Error: Type 'string' is not assignable to type 'number'
const count: number = getUserCount(); // getUserCount returns string
AI Fix suggests:
const count: number = parseInt(getUserCount(), 10);
Or alternatively:
const count: number = Number(getUserCount());
Errors in the terminal (runtime errors, build failures, test failures) often contain useful information buried in verbose output. Cursor's AI can parse through the noise.
Interpreting build errors:
When your build fails, the terminal shows output like:
ERROR in ./src/components/Dashboard.tsx
Module not found: Error: Can't resolve './charts/LineChart'
in '/Users/dev/project/src/components'
Select this text in the terminal, press Cmd+L / Ctrl+L, and ask:
This build error appeared. What's wrong and how do I fix it?
The AI will explain that the import path is wrong, suggest checking for typos in the filename, and might identify that the file was moved or renamed.
Interpreting stack traces:
Long stack traces can be overwhelming. The AI excels at finding the relevant line:
Error: ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)
at Protocol._enqueue (/node_modules/pg/lib/protocol.js:28:4)
at Client.query (/node_modules/pg/lib/client.js:132:16)
at Object.getUsers (/src/db/queries.js:15:23)
at router.get (/src/routes/users.js:8:28)
Ask the AI: "What's causing this connection error and what should I check?"
The AI will explain:
- The PostgreSQL database at port 5432 is refusing connections
- Check if the database server is running
- Verify connection settings (host, port, credentials)
- The error originates from
queries.js:15in your code
Terminal error workflow:
- See an error in the integrated terminal (Ctrl+`)
- Select the error text (triple-click for a line, or drag to select multiple lines)
- Press Cmd+L to send to Chat
- Ask your question about the error
- If the AI suggests a code fix, navigate to the file and apply it
- See an error in the integrated terminal (Ctrl+`)
- Select the error text (triple-click for a line, or drag to select multiple lines)
- Press Ctrl+L to send to Chat
- Ask your question about the error
- If the AI suggests a code fix, navigate to the file and apply it
Test failure interpretation:
When a test fails with an assertion error:
FAIL src/utils/format.test.js
● formatCurrency › formats USD correctly
expect(received).toBe(expected)
Expected: "$1,234.56"
Received: "$1234.56"
12 | test('formats USD correctly', () => {
13 | const result = formatCurrency(1234.56, 'USD');
> 14 | expect(result).toBe('$1,234.56');
15 | });
The AI can explain: "Your formatCurrency function isn't adding thousand separators. It outputs $1234.56 instead of $1,234.56. You need to add locale-aware number formatting — use Intl.NumberFormat or add comma insertion logic."
Complex bugs rarely get fixed on the first try. Chat's multi-turn nature makes it ideal for iterative debugging.
The debugging conversation pattern:
Turn 1: "I have this error: [paste error]. Here's the relevant code: [select code + Cmd+L]"
Turn 2: [AI suggests a fix] → You apply it → still broken
Turn 3: "That didn't fix it. Now I'm getting a different error: [new error]"
Turn 4: [AI adjusts approach] → You apply → partially works
Turn 5: "It works for most cases but fails when the input is empty. Here's the failing test."
Turn 6: [AI adds edge case handling] → Fixed!
Tips for effective debugging conversations:
- Report results honestly — tell the AI exactly what happened after each fix attempt
- Share new error messages — if a fix produces a different error, that's progress — share it
- Narrow the scope — "it's still broken" is less useful than "it works for strings but fails for numbers"
- Provide test cases — "When I pass
null, it throws. When I pass[], it returns the wrong value." - Ask for explanations — "Why did that fix work?" helps you understand and prevent similar bugs
When to start over:
If the conversation has gone 5+ turns without resolution:
- Start a new chat (click +)
- Summarise the problem fresh: "I've been trying to fix X. I've tried A, B, and C. None worked because [reasons]. What else should I try?"
- This gives the AI a clean context without potentially misleading earlier messages
Rubber duck debugging with AI:
Sometimes explaining the problem to the AI helps you spot the issue yourself:
"The function should return the total price including tax.
It takes an array of items, each with a price and quantity.
It multiplies price * quantity for each item, sums them,
then adds 8.5% tax. But the total is always wrong by...
wait, I think I see it — I'm adding tax per item instead of on the total."
The act of explaining can be as valuable as the AI's response.
For bugs that resist simple fixes — race conditions, state management issues, complex data flows — combine Cursor's built-in debugger with AI analysis.
Setting up the debugger:
- Click the left gutter to set a breakpoint (red dot appears)
- Open the Run and Debug panel (Cmd+Shift+D)
- Click "Run and Debug" or press F5
- When execution pauses at the breakpoint, inspect variables in the Debug panel
- Click the left gutter to set a breakpoint (red dot appears)
- Open the Run and Debug panel (Ctrl+Shift+D)
- Click "Run and Debug" or press F5
- When execution pauses at the breakpoint, inspect variables in the Debug panel
The Debugger + AI workflow:
- Set breakpoints at suspicious locations
- Run the debugger and trigger the bug
- Inspect variable values at the breakpoint
- Copy the variable state into Chat:
At this breakpoint, the variables are: - users = [{id: 1, name: null}, {id: 2, name: "Alice"}] - filterActive = true - result = undefined I expected result to be an array of active users. Why is it undefined? - The AI can reason about the data and logic to identify where things go wrong
What to share with the AI from the debugger:
| Debugger Info | How to Share |
|---|---|
| Variable values | Copy from Variables panel into Chat |
| Call stack | Screenshot or type the function chain |
| Watch expressions | Copy the expression results |
| Console output | Select from Debug Console |
| Conditional breakpoint hits | Describe when it triggers vs when it doesn't |
Example: Debugging a state issue
You: I have a React component that should show a loading spinner
while data fetches, then show the data. But it briefly flashes
the data, then shows the spinner, then shows data again.
At the breakpoint in useEffect:
- isLoading = false (should be true at this point)
- data = [] (correct initially)
- fetchCount = 2 (why is this 2? It should be 1)
Here's the component: @src/components/UserList.jsx
AI: The issue is that your useEffect is running twice due to
React.StrictMode in development. The second invocation starts
before the first completes, causing the flash. Your state
updates are interleaving. Here's how to fix it with a cleanup
function and an AbortController...
When to use Debugger + AI vs just AI:
| Scenario | Approach |
|---|---|
| Error message is clear | AI alone (explain + fix) |
| Bug is about wrong values | Debugger to inspect, then AI to reason |
| Bug is intermittent | Debugger with conditional breakpoints + AI |
| Bug involves timing/async | Debugger to trace execution order + AI |
| Bug is in logic you wrote | Often AI alone is sufficient |
| Bug is in framework interaction | Debugger + AI + @docs |
Here are complete workflows for the most common debugging scenarios in Cursor:
Workflow 1: Type Error (quick fix)
- See red squiggly on a line
- Press Cmd+. / Ctrl+. for lightbulb
- Select "Fix with AI"
- Accept the diff
- Done — typically under 30 seconds
Workflow 2: Runtime Error (medium complexity)
- Error appears in terminal
- Select error + stack trace
- Press Cmd+L / Ctrl+L → "Explain this error"
- AI identifies the file and line
- Navigate to the file (click the filename in the AI response)
- Select the function, press Cmd+K: "Fix the null reference error"
- Accept and re-run
Workflow 3: Logic Bug (higher complexity)
- Test fails or wrong output observed
- Open Chat, share the expected vs actual behaviour
- Reference the relevant file:
@src/utils/calculator.js The calculateDiscount function returns wrong values for bulk orders over 100 items - AI suggests a hypothesis
- Add a breakpoint to verify the hypothesis
- Share debugger findings in Chat
- AI refines the fix
- Apply and test
Workflow 4: "It works locally but fails in CI"
- Copy the CI error log into Chat
- Ask: "This passes locally but fails in CI. What environment differences could cause this?"
- AI suggests: timezone differences, file path separators, missing env vars, package version mismatches
- Investigate each suggestion
- Report back to Chat with findings
- Iterate until resolved
Workflow 5: Performance Bug
- Describe the symptom: "The API response takes 5 seconds for this endpoint"
- Reference the route:
@src/routes/search.js - Ask: "What could cause slow performance in this handler?"
- AI identifies: N+1 queries, missing indexes, unnecessary data fetching
- Apply suggested optimisations one at a time, measuring between each
Questions & Answers
Key Takeaways
- Explain first, fix second — always understand the error before applying a fix
- Lightbulb (Cmd+. / Ctrl+.) for quick one-line fixes — fast and reliable for type/syntax errors
- Terminal errors into Chat — select, press Cmd+L / Ctrl+L, ask for explanation
- Iterate honestly — tell the AI exactly what happened after each fix attempt
- Debugger provides facts, AI provides reasoning — combine both for complex bugs
- Always test after fixing — AI-suggested fixes can introduce new bugs
Next Steps: In Lesson 6 — Custom Rules & .cursor/rules, you'll learn how to configure project-specific AI behaviour so Cursor generates code that matches your team's conventions.