I'd like to strip the reactive DefaultErrorAttributes to only expose timestamp and message fields in the json response. Especially, I want to get rid of the status field in the json response, as this is already clear from the http response header.

While https://github.com/spring-projects/spring-boot/issues/30011 is marked as fixed (a NPE is not thrown anymore), it does not help. Because WebTestClient assertions still rely on the existence of a status field inside the json response (instead it should rely on the HTTP status header response).

@Component
public class ReactiveHidingDefaultErrorAttributes extends org.springframework.boot.web.reactive.error.DefaultErrorAttributes {

    @Override
    public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        Map<String, Object> map = super.getErrorAttributes(request, options);
        map.keySet().retainAll(Set.of("timestamp", "message"));
        return map;
    }

}

@RestController
public class ExampleServlet {
    @GetMapping("/test")
    public Mono<String> greeting(ServerHttpRequest request) {
        throw new ResponseStatusException(HttpStatus.I_AM_A_TEAPOT, "junit");
    }
}

@SpringBootTest(properties = "spring.main.web-application-type=reactive")
@AutoConfigureWebTestClient
public class ReactiveDefaultExceptionHandlerTest
    @Test
    public void test() {
        webTestClient.get().uri("/test")
                .exchange()
                .expectStatus().isEqualTo(HttpStatus.I_AM_A_TEAPOT);
    }
}

The test fails with:

2024-08-12T14:47:13.735+02:00 ERROR 72375 --- [     parallel-2] o.s.w.s.a.HttpWebHandlerAdapter          : [7292913d] 500 Server Error for HTTP GET "/status"

java.lang.IllegalStateException: ErrorAttributes must contain a status integer
    at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-6.1.11.jar:6.1.11]
    at org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler.getHttpStatus(DefaultErrorWebExceptionHandler.java:244) ~[spring-boot-autoconfigure-3.3.2.jar:3.3.2]
    at org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler.renderErrorResponse(DefaultErrorWebExceptionHandler.java:151) ~[spring-boot-autoconfigure-3.3.2.jar:3.3.2]
    at org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler.lambda$handle$0(AbstractErrorWebExceptionHandler.java:299) ~[spring-boot-autoconfigure-3.3.2.jar:3.3.2]
    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) [reactor-core-3.6.8.jar:3.6.8]
    at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) [reactor-core-3.6.8.jar:3.6.8]
    at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) [reactor-core-3.6.8.jar:3.6.8]
    at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onNext(FluxConcatArray.java:180) [reactor-core-3.6.8.jar:3.6.8]

Comment From: philwebb

I think we had some trouble directly getting the status from the DefaultErrorWebExceptionHandler. Rather than using a custom DefaultErrorAttributes bean, are you able to plug in your own DefaultErrorWebExceptionHandler and override the getErrorAttributeOptions method to exclude STATUS?

Comment From: membersound

Even if so, that would be quite error-prone, as I'd have to replace the @Bean definition from ErrorWebFluxAutoConfiguration.

Which in turn means, for every spring-boot release I'd have to check if the bean definition changes from current:

public class ErrorWebFluxAutoConfiguration { @Bean @ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT) @Order(-1) public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties, ObjectProvider<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) { DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes, webProperties.getResources(), this.serverProperties.getError(), applicationContext); exceptionHandler.setViewResolvers(viewResolvers.orderedStream().toList()); exceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters()); exceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders()); return exceptionHandler; } }

If there would be some kind of Configurer similar to WebFluxConfigurer that could be used to modify the bean creation, then I could imagine the approach might work. But not as is.

Comment From: philwebb

@membersound I think #41732 should have fixed this.