What does Spring Boot's DefaultErrorWebExceptionHandler do, and how would you customize the error response it produces?
answer
- Boot class, ErrorWebFluxAutoConfiguration, order -1
- extends AbstractErrorWebExceptionHandler
- getRoutingFunction -> content-negotiated JSON/HTML
- Body from ErrorAttributes (DefaultErrorAttributes)
- Customize: properties -> ErrorAttributes -> subclass -> own handler
basics
~20 sIt is Spring Boot's global fallback error handler for WebFlux. It renders a JSON (or Whitelabel HTML) error response for any unhandled exception, using ErrorAttributes for the body. Customize it by supplying your own ErrorAttributes or by subclassing AbstractErrorWebExceptionHandler.
solid answer
~40 s`DefaultErrorWebExceptionHandler` is registered by Spring Boot's `ErrorWebFluxAutoConfiguration` as an `ErrorWebExceptionHandler` (a `WebExceptionHandler`) at order -1, so it fronts the chain and owns error rendering. It extends `AbstractErrorWebExceptionHandler`, which stores the error via `DefaultErrorAttributes` and exposes a `RouterFunction` (`getRoutingFunction`) that routes to an error handler producing either JSON (for API clients) or an HTML Whitelabel page (for browsers, based on Accept). The body content comes from an `ErrorAttributes` bean. Customization options, least to most invasive: (1) tune what fields appear via `server.error.include-message`/`include-stacktrace`/`include-binding-errors` properties; (2) provide a custom `ErrorAttributes` bean (usually extending `DefaultErrorAttributes`) to add/rename fields; (3) subclass `AbstractErrorWebExceptionHandler` and override `getRoutingFunction` for full control of routing and rendering; or (4) skip it entirely with a higher-precedence `WebExceptionHandler`. The autoconfiguration backs off if you define your own `ErrorWebExceptionHandler` bean.
code
java · 28 lines// Full control: subclass AbstractErrorWebExceptionHandler and own the routing.
@Component
@Order(-2) // ahead of Boot's DefaultErrorWebExceptionHandler (-1)
public class JsonOnlyErrorHandler extends AbstractErrorWebExceptionHandler {
public JsonOnlyErrorHandler(ErrorAttributes errorAttributes,
WebProperties webProperties,
ApplicationContext applicationContext,
ServerCodecConfigurer codecConfigurer) {
super(errorAttributes, webProperties.getResources(), applicationContext);
setMessageWriters(codecConfigurer.getWriters());
setMessageReaders(codecConfigurer.getReaders());
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderJson);
}
private Mono<ServerResponse> renderJson(ServerRequest request) {
Map<String, Object> attrs = getErrorAttributes(request,
ErrorAttributeOptions.of(ErrorAttributeOptions.Include.MESSAGE));
int status = (int) attrs.getOrDefault("status", 500);
return ServerResponse.status(status)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(attrs);
}
}go deeper
Know Boot gives you a default error response out of the box.
Know it uses ErrorAttributes and can be tuned via server.error.* properties.
Explain the customization ladder and the -1 ordering / back-off condition.
Design a consistent org-wide error contract and decide the right override layer for mixed clients.
## Where it comes from `DefaultErrorWebExceptionHandler` is **not** part of core WebFlux — it is a **Spring Boot** class, auto-registered by `ErrorWebFluxAutoConfiguration`. It implements `ErrorWebExceptionHandler`, a marker interface that extends `WebExceptionHandler`. Boot orders it at `-1` (`@Order(-1)`) so it runs ahead of the core WebFlux handlers and becomes the effective global fallback that turns any unhandled `Throwable` into a proper HTTP error response. ## What it produces It extends `AbstractErrorWebExceptionHandler`, whose job is to: 1. Take the stored error (put into the exchange attributes by `DefaultErrorAttributes`) and 2. Route the request through a `RouterFunction<ServerResponse>` returned by the abstract `getRoutingFunction(ErrorAttributes)` method. `DefaultErrorWebExceptionHandler.getRoutingFunction` routes **all** requests to a single `renderErrorResponse` method that content-negotiates: - `Accept: text/html` (browsers) -> an HTML **Whitelabel error page** (or your `error/*.html` templates / static `error/4xx.html` etc.). - otherwise -> a **JSON** body built from `ErrorAttributes`. The default JSON body fields: `timestamp`, `path`, `status`, `error`, `requestId`, and optionally `message`, `errors` (binding errors), `trace` (stacktrace) — the last three are controlled by properties. ## HTTP status resolution The status is derived from the exception: `ResponseStatusException`/`@ResponseStatus` -> that status; otherwise 500. `DefaultErrorAttributes` reads this to populate `status`/`error`. ## Customization ladder (least to most invasive) 1. **Properties** — control which fields leak: - `server.error.include-message=always|never|on-param` - `server.error.include-stacktrace=never|always|on-param` - `server.error.include-binding-errors=never|always|on-param` - `server.error.whitelabel.enabled=false` to disable the HTML page. 2. **Custom `ErrorAttributes` bean** — extend `DefaultErrorAttributes` and override `getErrorAttributes(ServerRequest, ErrorAttributeOptions)` to add/remove/rename fields (e.g., add an `errorCode`). This is the most common and least fragile customization; `DefaultErrorWebExceptionHandler` will use your bean automatically. 3. **Subclass `AbstractErrorWebExceptionHandler`** — override `getRoutingFunction` to fully control routing (e.g., different responses per path) and body rendering. You must register it as a bean; typically copy Boot's constructor wiring (`ErrorAttributes`, `WebProperties.Resources`, `ServerCodecConfigurer`, `ApplicationContext`) and set its order to -1. 4. **Own `WebExceptionHandler`** at a lower order to pre-empt Boot entirely. ## Backing off `ErrorWebFluxAutoConfiguration` uses `@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)` — define your own `ErrorWebExceptionHandler` bean and Boot's default steps aside. ## Gotchas - In production, do NOT set `include-stacktrace=always` — it leaks internals. - The Whitelabel page vs JSON split is Accept-header driven; a `curl` without `Accept: application/json` may still receive JSON (default) because Boot treats non-HTML accepts as JSON, but a browser gets HTML — test with the real client. - This handler is the reason a functional endpoint or filter error still yields a clean 500 JSON even without any `@ControllerAdvice`. - It only fires for errors that reach the WebExceptionHandler chain; an exception fully handled by `@ExceptionHandler` never reaches it.
- How does DefaultErrorWebExceptionHandler decide between JSON and the Whitelabel HTML page?Via content negotiation on the Accept header. text/html requests get the HTML Whitelabel (or your error templates); everything else gets a JSON body built from ErrorAttributes.
- How does Boot know to back off when you provide your own handler?ErrorWebFluxAutoConfiguration registers the default under @ConditionalOnMissingBean(ErrorWebExceptionHandler.class), so any user-defined ErrorWebExceptionHandler bean disables the default.
saying these in an interview costs you the question
- Claiming DefaultErrorWebExceptionHandler is part of core spring-webflux (it's Spring Boot)
- Leaving include-stacktrace=always in production
- Thinking you must subclass it just to add a field (an ErrorAttributes bean suffices)