Skip to content

Error-Driven Development

Your CI pipeline is red. There are 14 TypeScript errors, 3 failing tests, and a deprecation warning. Your instinct is to fix them yourself or to paste the whole error log into the AI and say “fix everything.” Both approaches waste time. Fixing them yourself ignores your AI’s ability to resolve mechanical issues. Dumping the entire log gives the AI too much to process at once and leads to cascading “fixes” that introduce new problems.

Error-driven development treats each error as a precise, machine-generated specification. An error message tells the AI exactly what is wrong, where it is wrong, and what the system expects instead. That is better than any prompt you could write from scratch.

  • A systematic workflow for feeding errors to your AI assistant one at a time
  • Prompts that extract maximum signal from error messages
  • Strategies for breaking error cascades (where fixing one error creates three more)
  • Techniques for using errors as learning opportunities that improve your CLAUDE.md, .cursor/rules, and AGENTS.md

Instead of trying to prevent all errors, you lean into them as the fastest feedback mechanism available. The loop is simple:

  1. Make a change (or let the AI make one)
  2. Run the verification step (build, test, lint, type-check)
  3. Read the first error
  4. Feed it to the AI with targeted context
  5. Let the AI fix the root cause
  6. Repeat from step 2

The critical discipline is one error at a time. Error messages often cascade — a single root cause produces dozens of downstream errors. Fix the first one and half the others disappear.

The quality of the fix depends entirely on how you present the error. Do not just say “the build is broken.” Give the AI the exact error output, the file it occurred in, and what you expected to happen.

Cursor’s integrated terminal makes error-driven development seamless. Run your build or tests directly in the terminal, then reference the error in Agent mode:

I ran npm run type-check and got this error:
src/services/notification.ts:42:5 - error TS2345:
Argument of type 'string' is not assignable to parameter
of type 'NotificationPayload'.
Fix the root cause. The function signature in @src/services/notification.ts
expects a NotificationPayload object, not a raw string. Check the caller
at line 42 and the type definition in @src/types/notification.ts.

Cursor’s agent can also read terminal output directly. After a failing command, just type in chat: “Fix the error in the terminal.”

A common trap: the AI fixes error 1, which introduces error 2, which when fixed introduces error 3. You end up in a whack-a-mole cycle that burns through your context window without making progress.

The solution is to recognize cascading patterns and address them structurally.

When you see the same file appearing in multiple errors, zoom out:

We've been fixing errors in notification.ts for three iterations
and new ones keep appearing. Stop fixing individual errors.
Instead:
1. Read the full file @src/services/notification.ts
2. Read the types it depends on @src/types/notification.ts
3. Read the test file @src/services/__tests__/notification.test.ts
4. Identify the structural problem causing the cascade
5. Propose a fix for the root architectural issue
Do not modify any files until I approve the approach.

The most valuable errors are the ones you never see again. When you encounter a non-obvious error, capture the lesson in your project’s configuration so the AI avoids the same mistake in future sessions.

Add a project rule in .cursor/rules/errors.md:

---
description: "Common errors and their fixes for this project"
alwaysApply: true
---
## Known Error Patterns
- When modifying notification types, always update both
`src/types/notification.ts` AND the Zod schema in
`src/validators/notification.ts`. They must stay in sync.
- Redis connection errors in tests: run `docker compose up -d redis`
before running the test suite.

The error message is unhelpful. Some error messages are genuinely opaque (segfaults, generic “internal server error”). In these cases, switch from error-driven to hypothesis-driven: ask the AI to add logging, reproduce the issue, and narrow down the cause through elimination.

The AI keeps suppressing errors instead of fixing them. If you see @ts-ignore, as any, empty catch blocks, or eslint-disable in the AI’s output, it is suppressing symptoms rather than fixing causes. Be explicit: “Do not suppress errors. Fix the underlying issue.”

Too many errors to process. If type-check produces 200+ errors, do not feed them all to the AI. Focus on the first 3-5 errors — they are usually the root causes that produce the rest. After fixing those, re-run and check how many remain.

The error is in generated code. When the error is in a file the AI generated from scratch, it is often faster to delete the file and regenerate it with a more constrained prompt than to patch the existing broken version.