Errors & exception handling
A global GenieExceptionHandler (an IExceptionHandler, registered by AddGenie and activated by
app.UseGenieExceptionHandler() first in the pipeline) turns any unhandled exception into a
consistent JSON envelope with a status code mapped from the exception type — instead of the
framework’s default HTML error page or an empty 500.
The error envelope
Section titled “The error envelope”{ "success": false, "error": "The requested object was not found.", "traceId": "00-4bf9…-01"}successis alwaysfalsefor an error response.erroris the message (see detail exposure for when 5xx messages are masked).traceIdis the current activity id (or the request trace identifier) — quote it in bug reports; the full failure is always logged server-side against the same id.
When IncludeStackTrace is on, the body also carries exceptionType and stackTrace for local
debugging.
Status-code mapping
Section titled “Status-code mapping”Throw the right exception type from your services and let the handler shape the response — don’t
hand-roll BadRequest(new { message }) in new code.
| Exception type | Status |
|---|---|
UnauthorizedException, UnauthorizedAccessException |
401 |
NotFoundException, KeyNotFoundException |
404 |
ArgumentException |
400 |
ValidationException, RuntimeException, GenieException, InvalidOperationException |
400 |
| anything else | 500 |
Expected (4xx) errors are deliberate, safe feedback, so they always carry their real message. Only unexpected (5xx) failures are subject to detail masking.
Config: Genie:Errors
Section titled “Config: Genie:Errors”Whether 5xx bodies expose the real exception message is config-driven via the Genie:Errors section
(GenieErrorOptions) — on in dev, off in prod:
"Genie": { "Errors": { "ExposeErrorDetails": true, "IncludeStackTrace": false }}| Key | Default | Effect |
|---|---|---|
ExposeErrorDetails |
true |
When true, a 5xx returns the real exception message. When false, it returns a generic “An unexpected error occurred…” message and logs the detail only. Turn off in production. |
IncludeStackTrace |
false |
When true, the response also includes the exception type and full stack trace. Local debugging only — keep false outside Development. |
Override in code through the builder:
builder.Services.AddGenie<YourContext>(genie => genie .LoadFromConfiguration(builder.Configuration) .ConfigureErrors(e => { e.ExposeErrorDetails = false; // production e.IncludeStackTrace = false; }));