# Module: `Azaion.Missions.Middleware` > **NOTE (forward-looking)**: post-rename namespace. Today's source still lives under `Azaion.Flights.Middleware`. Renames tracked under Jira AZ-EPIC child B5. **Files (1)**: `Middleware/ErrorHandlingMiddleware.cs` ## Purpose Global exception → JSON error response mapper. Wraps the rest of the request pipeline and converts a fixed set of exception types to specific HTTP status codes; everything else becomes a 500. ## Public Interface ```csharp public class ErrorHandlingMiddleware(RequestDelegate next, ILogger logger) { public Task Invoke(HttpContext context); } ``` Standard ASP.NET Core middleware shape (primary-constructor variant). ## Internal Logic ```text try { await next(context); } catch (KeyNotFoundException ex) → 404 NotFound, body: { statusCode, message = ex.Message } catch (ArgumentException ex) → 400 BadRequest, body: { statusCode, message = ex.Message } catch (InvalidOperationException ex) → 409 Conflict, body: { statusCode, message = ex.Message } catch (Exception ex) → 500 InternalServerError, body: { statusCode, message = "Internal server error" } PLUS: logger.LogError(ex, "Unhandled exception"); ``` Body is serialized via `JsonSerializer.Serialize(new { statusCode, message })` — an **anonymous object literal**, NOT the `DTOs.ErrorResponse` type. The anonymous-type property names are written lowercase-first in code (`statusCode`, `message`); `System.Text.Json` preserves them as-is when no `JsonNamingPolicy` is configured, so the wire shape is `{"statusCode":..., "message":"..."}` — **camelCase by accidental match with the suite spec**. (The unused `DTOs.ErrorResponse` type, by contrast, declares PascalCase properties and would serialize PascalCase if it were ever used directly.) `Content-Type` is set to `application/json`. Response body is written via `WriteAsync` (string). ## Dependencies - `System.Net` (`HttpStatusCode`) - `System.Text.Json` (`JsonSerializer`) - ASP.NET Core middleware abstractions (transitive via `Microsoft.NET.Sdk.Web`) - `Microsoft.Extensions.Logging.ILogger` (transitive) No internal dependencies. ## Consumers - `Program.cs` — `app.UseMiddleware();` is called BEFORE `UseCors`, `UseAuthentication`, `UseAuthorization`, `UseSwagger`, `UseSwaggerUI`, `MapControllers`. ## Configuration / External Integrations / Security None. ## Tests None present. ## Notes / Smells 1. **`DTOs.ErrorResponse` is unused here** — middleware writes an anonymous object instead. **Partial spec divergence**: `../../suite/_docs/00_top_level_architecture.md` § Error Response Format mandates `{ "statusCode", "message", "errors": object? }` (camelCase, `errors` is an *object* of per-field arrays). The middleware's anonymous-object output IS already camelCase on case (`{"statusCode":..., "message":"..."}`) but missing the `errors` field; the static `ErrorResponse` DTO has the wrong shape (`List? Errors` instead of `object?`) and is dead code. 2. **Entity / DTO body case-style** is PascalCase across the rest of the API (controller responses serialize entities and `PaginatedResponse` via `System.Text.Json` defaults with no naming policy override). The error envelope's accidental camelCase match documented in point 1 does NOT extend to those responses — see `architecture.md` ADR-002. 3. **`InvalidOperationException` → 409 Conflict** is a non-standard mapping. The .NET BCL throws this for many "wrong state at the moment" conditions; in this codebase it is used by `VehicleService.DeleteVehicle` to report "vehicle is referenced by missions" (a true 409). But any third-party library throwing `InvalidOperationException` for an unrelated reason would also surface as 409, masking the real cause. 4. **Generic 500 swallows the message** (good for security — no internal detail leaked) and logs the exception (good for diagnostics). No correlation ID is included in the response, so production support has to grep logs by timestamp. 5. **Order of catches** matters: `ArgumentException` is base of `ArgumentNullException` / `ArgumentOutOfRangeException`, so those also become 400 (correct). `InvalidOperationException` ahead of generic `Exception` is correct.