Teach Cursor to use Result<T> instead of throw in C#
Your team standardised on Result<T> (or ErrorOr, or your own discriminated-union helper). Yet every new method Cursor writes uses throw new InvalidOperationException(...) or returns null. You correct it. The next prompt forgets. This is not a model intelligence problem — it is a rule problem. Here is the one Cursor rule that teaches the AI to respect the pattern across sessions.
The short answer
Cursor will keep suggesting throw until you commit a .cursor/rules/error-model.mdc file that says, in plain language, "this codebase returns Result<T>, never throws for expected failure paths." Without that rule, the AI defaults to the dominant pattern in its training data — which is exception-based error handling, because that is what Stack Overflow shows. With it, the AI defaults to your project's pattern, because the rule loads on every prompt that touches a return type.
Why your corrections don't stick
When you tell Cursor "use Result<T> not throw", you are giving it a one-shot instruction inside a chat. The next chat — or the next time the context window rolls over — that instruction is gone. The model goes back to its training-data prior, which is most C# code in the wild throws. You are not fighting the AI; you are fighting the statistical centre of gravity of every C# tutorial ever written.
A committed rule wins because it is loaded into the AI's context every prompt, not once. It does not rely on you remembering to re-explain.
What the rule should contain
A useful error-model.mdc covers four things:
- The error type. "This project uses
Result<T>fromFluentResults" or "usesErrorOr<T>fromErrorOr". Be explicit about the namespace and the helper. - The forbidden patterns. No
throwfor expected business failures (validation, not-found, conflict). No method that returnsT?whereResult<T>is the established alternative. - The allowed exceptions.
throwis still acceptable for genuinely exceptional, unrecoverable situations (bug guards, missing required configuration at startup, etc.). Make the boundary explicit so the AI doesn't over-correct. - The composition pattern. Show one example:
Result.Try(...),.Map,.Bind, or whatever your chosen library uses for chaining. The AI will pattern-match against the example.
The fix in 60 seconds
Add a 30-line error-model.mdc to .cursor/rules/ with the four points above. Commit it. The very next prompt that touches a service method will return Result<T> by default. You will still get the occasional drift — usually when Cursor is editing code outside your service layer — at which point you can either scope the rule more tightly (only on files under /Application/, for example) or accept the friction at the boundary.
Want the full picture?
The long-form essay walks through the worked example with FluentResults, shows the exact rule content, and covers the edge cases (FluentValidation results, MediatR handlers, ASP.NET Core minimal-API endpoints).
→ Read: Teach Cursor Result<T> instead of throwing
Try the boundary rule for free
The arch-core-lite.mdc rule is the boundary-guardian preview from the kit — it enforces the architectural boundary on every Cursor suggestion. No signup, no email.
Or get the full kit (four rules + Learning Log engine).
The complete Agentic Architect kit — 4 specialist rules + the persistence engine for teaching Cursor your project's decisions — is £19.99 one-time. Lifetime updates. MIT-licensed. 14-day refund.
Get Agentic Architect — £19.99 →