ErrorLens.ErrorHandling 1.4.0

dotnet add package ErrorLens.ErrorHandling --version 1.4.0
                    
NuGet\Install-Package ErrorLens.ErrorHandling -Version 1.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ErrorLens.ErrorHandling" Version="1.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ErrorLens.ErrorHandling" Version="1.4.0" />
                    
Directory.Packages.props
<PackageReference Include="ErrorLens.ErrorHandling" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ErrorLens.ErrorHandling --version 1.4.0
                    
#r "nuget: ErrorLens.ErrorHandling, 1.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ErrorLens.ErrorHandling@1.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ErrorLens.ErrorHandling&version=1.4.0
                    
Install as a Cake Addin
#tool nuget:?package=ErrorLens.ErrorHandling&version=1.4.0
                    
Install as a Cake Tool

Banner

ErrorLens.ErrorHandling

NuGet NuGet OpenApi NuGet Swashbuckle NuGet FluentValidation Build License: MIT .NET 6.0+

Transform unhandled exceptions into clean, structured JSON responses with minimal setup — just two lines of code to get started.

ErrorLens provides a production-ready error handling pipeline for ASP.NET Core APIs. Every exception is automatically converted into a consistent, structured JSON response with appropriate HTTP status codes, machine-readable error codes, and human-readable messages. The library handles the full lifecycle from exception to response: handler selection, response customization, secure 5xx safe messaging, configurable logging, and optional localization — with zero-config defaults that work out of the box and deep extensibility when you need it.

Full documentation: https://ahmedv20.github.io/error-handling-dotnet/current/


Features

  • Zero-Config Exception Handling — Unhandled exceptions return structured JSON error responses out of the box
  • Validation Error Details — Field-level errors with property names, messages, and rejected values
  • Secure Error Responses — 5xx errors return generic safe messages to prevent information disclosure
  • Custom JSON Field Names — Rename any response field (codetype, messagedetail, etc.)
  • YAML & JSON Configuration — Configure error codes, messages, HTTP statuses via appsettings.json or errorhandling.yml
  • Custom Exception Attributes[ResponseErrorCode], [ResponseStatus], [ResponseErrorProperty]
  • Custom Exception Handlers — Register IApiExceptionHandler implementations with priority ordering
  • AggregateException Unwrapping — Automatically flattens and unwraps single-inner AggregateException
  • Response Customization — Add global properties (traceId, timestamp) via IApiErrorResponseCustomizer
  • Replaceable Mappers — Override IErrorCodeMapper, IErrorMessageMapper, or IHttpStatusMapper
  • RFC 9457 Problem Details — Opt-in application/problem+json compliant responses
  • Configurable Logging — Control log levels and stack trace verbosity per HTTP status code
  • Startup Validation — JSON field names validated at startup (non-null, non-empty, unique)
  • Multi-Target Support — .NET 6.0, 7.0, 8.0, 9.0, and 10.0
  • .NET 8+ Native Integration — Automatically registers IExceptionHandler on .NET 8+; falls back to middleware on .NET 6/7
  • OpenTelemetry Tracing — Automatic Activity spans with error tags and OTel semantic conventions
  • Error Message LocalizationIErrorMessageLocalizer with IStringLocalizer bridge for multi-language support
  • OpenAPI / Swagger Integration — Auto-add error response schemas to API docs
  • Rate Limiting — Structured 429 responses with Retry-After headers via IRateLimitResponseWriter (.NET 7+)
  • Built-in Error Code ConstantsDefaultErrorCodes class with 23 predefined codes for consistent frontend matching
  • FluentValidation Integration — First-party support for FluentValidation with automatic error code mapping and severity filtering
  • Configurable Error Messages — Customize 5xx fallback message and override built-in handler messages via FallbackMessage and BuiltInMessages
  • 5 Error Code StrategiesAllCaps, FullQualifiedName, KebabCase, PascalCase, DotSeparated

Quick Start

Installation

dotnet add package ErrorLens.ErrorHandling

Minimal API (.NET 6+)

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddErrorHandling();

var app = builder.Build();
app.UseErrorHandling();

app.MapGet("/", () => { throw new Exception("Something went wrong"); });
app.Run();

Controller-Based API

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddErrorHandling();

var app = builder.Build();
app.UseErrorHandling();
app.MapControllers();
app.Run();

With Configuration Options

// Option 1: Inline options
builder.Services.AddErrorHandling(options =>
{
    options.HttpStatusInJsonResponse = true;
    options.OverrideModelStateValidation = true;
    options.IncludeRejectedValues = true;
    options.ExceptionLogging = ExceptionLogging.WithStacktrace;
});

// Option 2: Bind from appsettings.json / YAML
builder.Services.AddErrorHandling(builder.Configuration);

Note (.NET 8+): ErrorLens automatically registers IExceptionHandler on .NET 8+, so exceptions are handled natively by the ASP.NET Core exception handler pipeline. On .NET 6/7, UseErrorHandling() registers middleware instead. Both paths produce identical results.

All unhandled exceptions now return structured JSON:

{
  "code": "INVALID_OPERATION",
  "message": "The operation is not valid."
}

The error code is generated automatically from the exception class name using ALL_CAPS strategy — InvalidOperationException becomes INVALID_OPERATION, UserNotFoundException becomes USER_NOT_FOUND.

How It Works

ErrorLens processes exceptions through a pipeline with clearly defined stages:

Exception thrown
  → Handler Selection (sorted by Order, first CanHandle() match wins)
    → Fallback Handler (if no handler matches)
      → HTTP Status in JSON (if configured)
        → Response Customizers (all IApiErrorResponseCustomizer run in order)
          → Logging (ILoggingService with ILoggingFilter checks)
            → Localization (IErrorMessageLocalizer replaces messages)
              → OpenTelemetry (Activity enriched with error tags)
                → JSON Response (or Problem Details if enabled)

Each stage is independently configurable and replaceable. If any handler or customizer throws, the pipeline catches the error, logs both exceptions, and returns a safe 500 response to prevent cascading failures.

For a detailed architecture overview with Mermaid diagrams, see docs/ARCHITECTURE.md.

Packages

Package Description Target Frameworks Version
ErrorLens.ErrorHandling Core middleware for structured error responses .NET 6, 7, 8, 9, 10 NuGet
ErrorLens.ErrorHandling.OpenApi OpenAPI schema generation (.NET 9+) .NET 9, 10 NuGet
ErrorLens.ErrorHandling.Swashbuckle Swashbuckle integration (.NET 6-8) .NET 6, 7, 8 NuGet
ErrorLens.ErrorHandling.FluentValidation FluentValidation integration .NET 6, 7, 8, 9, 10 NuGet
# Optional integration packages
dotnet add package ErrorLens.ErrorHandling.OpenApi        # .NET 9+
dotnet add package ErrorLens.ErrorHandling.Swashbuckle    # .NET 6-8
dotnet add package ErrorLens.ErrorHandling.FluentValidation  # .NET 6-10

Default HTTP Status Mappings

ErrorLens maps common .NET exception types to appropriate HTTP status codes out of the box:

Exception Type HTTP Status
ArgumentException / ArgumentNullException 400 Bad Request
InvalidOperationException 400 Bad Request
FormatException 400 Bad Request
UnauthorizedAccessException 401 Unauthorized
KeyNotFoundException 404 Not Found
FileNotFoundException / DirectoryNotFoundException 404 Not Found
TimeoutException 408 Request Timeout
OperationCanceledException 499 Client Closed Request
NotImplementedException 501 Not Implemented
All others 500 Internal Server Error

Note: TaskCanceledException inherits from OperationCanceledException, so it also maps to 499 automatically.

Override any mapping via configuration or [ResponseStatus] attributes.

Configuration

ErrorLens supports both JSON (appsettings.json) and YAML (errorhandling.yml) configuration. Here is a minimal example:

{
  "ErrorHandling": {
    "HttpStatusInJsonResponse": true,
    "OverrideModelStateValidation": true,
    "IncludeRejectedValues": true,
    "ExceptionLogging": "WithStacktrace",
    "HttpStatuses": {
      "MyApp.UserNotFoundException": 404
    },
    "Codes": {
      "MyApp.UserNotFoundException": "USER_NOT_FOUND"
    }
  }
}

For YAML configuration:

ErrorHandling:
  HttpStatusInJsonResponse: true
  OverrideModelStateValidation: true
  IncludeRejectedValues: true
  ExceptionLogging: WithStacktrace
  HttpStatuses:
    MyApp.UserNotFoundException: 404
  Codes:
    MyApp.UserNotFoundException: USER_NOT_FOUND
builder.Configuration.AddYamlErrorHandling("errorhandling.yml");
builder.Services.AddErrorHandling(builder.Configuration);

Settings are resolved in this order (highest priority first):

  1. Custom exception handlersIApiExceptionHandler implementations
  2. Inline optionsAction<ErrorHandlingOptions> in AddErrorHandling()
  3. Configuration bindingappsettings.json or errorhandling.yml
  4. Exception attributes[ResponseErrorCode], [ResponseStatus]
  5. Default conventions — class name to ALL_CAPS, built-in HTTP status mappings

For the full configuration reference (all options, JSON field names, rate limiting, OpenAPI), see the Configuration Guide.

Exception Attributes

Decorate exception classes with attributes to control error responses declaratively:

[ResponseErrorCode("USER_NOT_FOUND")]
[ResponseStatus(HttpStatusCode.NotFound)]
public class UserNotFoundException : Exception
{
    [ResponseErrorProperty("userId")]
    public string UserId { get; }

    public UserNotFoundException(string userId)
        : base($"User {userId} not found") => UserId = userId;
}

Response:

{
  "code": "USER_NOT_FOUND",
  "message": "User abc-123 not found",
  "userId": "abc-123"
}
Attribute Target Description
[ResponseErrorCode("CODE")] Class Sets a custom error code
[ResponseStatus(HttpStatusCode.NotFound)] Class Sets the HTTP status code (accepts HttpStatusCode enum)
[ResponseStatus(404)] Class Sets the HTTP status code (accepts int, must be 100-599)
[ResponseErrorProperty("name")] Property Includes the property in the JSON response

For more details, see Exception Attributes.

Validation Errors

Enable OverrideModelStateValidation to get structured field-level validation errors:

builder.Services.AddErrorHandling(options =>
{
    options.OverrideModelStateValidation = true;
});

Response:

{
  "code": "VALIDATION_FAILED",
  "message": "Validation failed",
  "fieldErrors": [
    {
      "code": "INVALID_EMAIL",
      "property": "email",
      "message": "Invalid email format",
      "rejectedValue": "bad",
      "path": "email"
    }
  ]
}

Validation error codes and messages can be customized via configuration. See the Configuration Guide for details.

Security

All 5xx-class errors (500-599) automatically return a generic safe message instead of the raw exception message. The default message can be customized via ErrorHandlingOptions.FallbackMessage:

{
  "code": "INTERNAL_SERVER_ERROR",
  "message": "An unexpected error occurred"
}

This prevents internal details (database connection strings, file paths, stack traces) from leaking to API consumers. The original exception is still logged with full details on the server side. The BadRequestExceptionHandler also sanitizes Kestrel-internal error messages automatically.

Samples

Sample Description Key Features
MinimalApiSample Zero-config minimal API Default error handling, automatic error codes
FullApiSample Controller-based API with extensibility Custom handlers, response customizers, logging filters, Swagger
ShowcaseSample Full feature showcase with YAML YAML config, JSON field names, attributes, Problem Details, Swashbuckle
IntegrationSample Modern .NET ecosystem integration OpenTelemetry, localization, OpenAPI, rate limiting

Documentation

Documentation site: https://ahmedv20.github.io/error-handling-dotnet/current/

Guides

Core Features

Integration Features

Reference

Prerequisites

  • .NET SDK 6.0 or later (multi-targeting builds require .NET 10.0 SDK)
  • ASP.NET Core application (Minimal API or Controller-based)

Building from Source

git clone https://github.com/AhmedV20/error-handling-dotnet.git
cd error-handling-dotnet
dotnet restore
dotnet build

Running Tests

dotnet test

Running Sample Projects

dotnet run --project samples/MinimalApiSample
dotnet run --project samples/ShowcaseSample

🤝 Contributing

See CONTRIBUTING.md for guidelines.

License

MIT License — see LICENSE for details.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on ErrorLens.ErrorHandling:

Package Downloads
ErrorLens.ErrorHandling.OpenApi

Microsoft.AspNetCore.OpenApi integration for ErrorLens.ErrorHandling — automatically adds error response schemas to your OpenAPI documentation (.NET 9+).

ErrorLens.ErrorHandling.Swashbuckle

Swashbuckle integration for ErrorLens.ErrorHandling — automatically adds error response schemas to your Swagger/OpenAPI documentation.

ErrorLens.ErrorHandling.FluentValidation

FluentValidation integration for ErrorLens.ErrorHandling — automatically catches FluentValidation.ValidationException and maps failures to structured API error responses with field errors, error codes, and rejected values.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.0 105 2/28/2026
1.3.1 123 2/21/2026
1.3.0 132 2/16/2026
1.1.1 91 2/12/2026
1.1.0 80 2/11/2026
1.0.0 116 2/10/2026

v1.4.0:
- New package: ErrorLens.ErrorHandling.FluentValidation (catches FluentValidation.ValidationException)
- Configurable FallbackMessage for 5xx error responses
- BuiltInMessages dictionary to override built-in handler messages
- Three new ErrorCodeStrategy options: KebabCase, PascalCase, DotSeparated
- RetryAfter field name customization in JsonFieldNames
- Enhanced configuration validation (ProblemDetailTypePrefix URI, RateLimiting fields)

v1.3.1:
- IncludeRejectedValues option to suppress sensitive data in validation errors
- Pipeline resilience: localization/telemetry errors no longer crash error handling
- OperationCanceledException propagates naturally instead of returning 500
- Field-specific localization with composite key support (fieldName.errorCode)
- ProblemDetails uses configured JsonFieldNames instead of hardcoded values
- Rate limiting header and retry-after rounding fixes
- Null guards for model constructors, case-insensitive field name validation

v1.3.0:
- OpenTelemetry distributed tracing via System.Diagnostics.Activity
- Localization support with IErrorMessageLocalizer and IStringLocalizer bridge
- New package: ErrorLens.ErrorHandling.OpenApi (.NET 9+ OpenAPI integration)
- New package: ErrorLens.ErrorHandling.Swashbuckle (Swagger integration for .NET 6-8)
- Rate limiting integration with IRateLimitResponseWriter
- AggregateException handler
- Options validation at startup
- Idempotent DI registration for custom handlers and customizers

v1.1.1:
- Fix: Register ILoggingService in DI container (logging was not working in v1.1.0)

v1.1.0:
- Custom JSON field names (rename code→type, message→detail, etc.)
- YAML configuration support via AddYamlErrorHandling()
- OverrideModelStateValidation option for [ApiController] validation interception
- ModelStateValidationExceptionHandler with structured fieldErrors format
- Professional documentation with AsciiDoc
- 175 tests (up from 142)

Full changelog: https://github.com/AhmedV20/error-handling-dotnet/blob/main/CHANGELOG.md