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:

  1. The error type. "This project uses Result<T> from FluentResults" or "uses ErrorOr<T> from ErrorOr". Be explicit about the namespace and the helper.
  2. The forbidden patterns. No throw for expected business failures (validation, not-found, conflict). No method that returns T? where Result<T> is the established alternative.
  3. The allowed exceptions. throw is 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.
  4. 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.

Download arch-core-lite.mdc →

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 →