Introduction
An API should return errors that are predictable for clients and useful for developers. If every controller constructs its own error response, clients may receive inconsistent formats, and sensitive implementation details can accidentally leak into production responses.
ASP.NET Core supports centralized exception handling and standardized Problem Details responses, allowing an application to manage unexpected failures consistently.
1. Use a standard error format
Problem Details provides a structured representation of an HTTP error. Common fields include:
- type: a URI identifying the problem type
- title: a short description
- status: the HTTP status code
- detail: an explanation suitable for the client
- instance: an identifier for the specific occurrence
Applications can also include extension properties for domain-specific information, provided they do not disclose sensitive data.
2. Register Problem Details and exception handling
In a modern ASP.NET Core application, configure the services and middleware in Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
app.MapControllers();
app.Run();
This is a starting point, not a complete error policy for every application. The actual response depends on the exception-handling configuration, environment, and installed middleware. Verify the behavior of the ASP.NET Core version you target.
3. Distinguish expected errors from unexpected exceptions
Not every error should be treated as a server failure.
For example:
- A missing resource should usually produce 404 Not Found.
- An unauthenticated request should usually produce 401 Unauthorized.
- An authenticated user without the required permission should usually receive 403 Forbidden.
- Invalid request data may produce 400 Bad Request.
- An unexpected exception generally indicates a server-side failure.
Map known business conditions to appropriate HTTP responses. Reserve generic exception handling for failures that the application did not explicitly anticipate.
4. Keep internal details out of responses
Avoid returning stack traces, database exception messages, file paths, connection strings, or internal hostnames to clients.
Log the detailed exception on the server, with suitable access controls and redaction. Return a safe message to the caller and, when useful, a correlation identifier that support staff can use to find the corresponding log entry.
Be careful not to log credentials, access tokens, or sensitive request payloads.
5. Make errors consistent and testable
Write integration tests for common error cases. Verify status codes, content types, response fields, and the absence of sensitive details.
Also test the middleware ordering and behavior in the production environment. An error response that works during development may behave differently when custom exception pages or reverse proxies are involved.
Conclusion
Centralized error handling makes APIs more predictable and reduces duplicated response logic. Use Problem Details as a consistent format, map expected failures deliberately, and keep internal diagnostics in protected logs rather than public responses.