# 6. Errors that never reach an advice [← 5. Content negotiation](05-content-negotiation.md) · [Index](../README.md) · Next: [7. Silent 500s →](07-silent-500s.md) `@ControllerAdvice` runs inside the `DispatcherServlet`. Three kinds of error happen before or around it. ## Exceptions thrown by servlet filters [`TenantHeaderFilter`](../src/main/java/com/ankurm/problems/web/TenantHeaderFilter.java) throws for a malformed header. No advice sees it; Tomcat forwards to `/error`, and even the `advice` profile answers with Boot's JSON. The fix is to own `/error`: [`ProblemDetailErrorController`](../src/main/java/com/ankurm/problems/advice/ProblemDetailErrorController.java) implements Boot's `ErrorController` (`org.springframework.boot.webmvc.error` in Boot 4), which makes `ErrorMvcAutoConfiguration` skip `BasicErrorController`. It builds the problem from `ErrorAttributes` and keeps the 5xx detail generic, because the message there is whatever a filter happened to throw. ## Spring Security's 401 and 403 Decided in the filter chain. By default the entry point calls `sendError(401)`, which also ends at `/error` - so the error controller alone turns them into problems ([`errors-only.txt`](output/errors-only.txt)): ``` HTTP/1.1 401 WWW-Authenticate: Basic realm="Realm", charset="UTF-8" Content-Type: application/problem+json {"detail":"Unauthorized","instance":"/admin/orders","status":401,"title":"Unauthorized"} ``` This project goes one step further with [`ProblemDetailSecurityHandlers`](../src/main/java/com/ankurm/problems/security/ProblemDetailSecurityHandlers.java) so the 401 keeps a precise `type` and its `WWW-Authenticate` header. Note it is registered for `httpBasic` as well as `exceptionHandling`: HTTP Basic has its own entry point and would otherwise bypass the one set on `exceptionHandling`. ## Writing a `ProblemDetail` yourself: use the application's mapper [`/diag/mixin`](../src/main/java/com/ankurm/problems/diag/DiagController.java) serialises one `ProblemDetail` with one extension member three ways ([`client-decoding.txt`](output/client-decoding.txt)): ``` "Spring Boot's JsonMapper bean": "{\"detail\":\"demo\",\"status\":409,\"title\":\"Conflict\",\"sku\":\"SKU-2\"}", "JsonMapper.builder().build()": "{\"detail\":\"demo\",\"instance\":null,\"properties\":{\"sku\":\"SKU-2\"},\"status\":409,\"title\":\"Conflict\",\"type\":null}", "new JsonMapper()": "{\"detail\":\"demo\",\"instance\":null,\"properties\":{\"sku\":\"SKU-2\"},\"status\":409,\"title\":\"Conflict\",\"type\":null}" ``` `ProblemDetail` is a plain bean; the flattening of `properties` and the omission of empty members come from `ProblemDetailJacksonMixin`, which the Boot-configured mapper has and a mapper you construct does not. An entry point that does `new ObjectMapper().writeValue(...)` - the version in most tutorials - produces a body that is not a valid problem document. Inject the `JsonMapper`.