How do you handle errors and return consistent error responses in a Web API?
Quick Answer
Use one central exception-handling middleware (or IExceptionHandler in .NET 8) that catches unhandled exceptions and returns a consistent ProblemDetails body (RFC 7807) with the right status code. Let [ApiController] auto-return 400 for validation. Never leak stack traces in production; log the detail server-side with a correlation id.
I have one place that handles errors — exception-handling middleware, or IExceptionHandler in .NET 8 — rather than try/catch in every controller. It maps known exception types to status codes and returns a ProblemDetails body so every error looks the same to the client: type, title, status, detail and a trace id that ties back to the server log. Validation is handled for free by [ApiController], which returns a 400 with the field errors. Expected outcomes like “not found” or “conflict” I return explicitly from the action. And in production the response never contains a stack trace — that goes in the log.
- Validation errors —
[ApiController]turns invalidModelStateinto a400with aValidationProblemDetailsbody automatically. - Expected domain errors — return them explicitly:
NotFound(),Conflict(),UnprocessableEntity(). - Unexpected exceptions — a single handler maps exception types to status codes (e.g.
NotFoundException→ 404, everything else → 500) and produces aProblemDetails. - Shape —
{ type, title, status, detail, instance, traceId }. Include atraceIdso support can find the log entry. - Don't wrap every action in try/catch; that's what the middleware is for.