all,
we have a large Spring WebFlux code-base that relies on certain @ExceptionHandler / @RestControllerAdvice. and we have a case for Exception.class that basically logs the exception as error and returns a certain model:
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestError handleUnknown(Exception exception) {
log.error(Optional.ofNullable(exception.getCause())
.map(Throwable::getMessage)
.orElse(exception.getMessage()),
exception);
return new RestError(exception);
}
It should only be used occasionally, because we have also extensive coverage for specific exceptions. But still, we would like to keep this fallback option.
Problem, however, happens when a certain type of issue is causing the exception in question - namely, Netty's AbortedException. An exception handler, in this case, tries to write response body, and we see a completely obscure [xxx] Error [java.lang.UnsupportedOperationException] for HTTP GET "/actuator/health/readiness", but ServerHttpResponse already committed (200 OK) in the logs. This has been bugging me for a long while and I figured something needs to be done it.
So, I've added a custom WebFilter with a SignalListener that now logs this UnsupportedOperationexception with it's stacktrace, and I see that the error is actually Connection has been closed BEFORE send operation and the UnsupportedOperationException happens when the response body is written and a Content-Length header is set, and for whatever reason, these Headers are read-only, thus UnsupportedOperationException:
java.lang.UnsupportedOperationException: null
at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:108)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ Exception handler com.company.common.exception.handler.RestExceptionHandler#handleUnknown(Exception), error="Connection has been closed BEFORE send operation" [DispatcherHandler]
*__checkpoint ⇢ com.company.common.monitoring.logging.raw.LoggingWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ com.breakwater.sitecheckerservice.common.config.ErrorLoggingWebFilter [DefaultWebFilterChain]
*__checkpoint ⇢ HTTP POST "/v1/some-url" [ExceptionHandlingWebHandler]
Original Stack Trace:
at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:108)
at org.springframework.http.HttpHeaders.setContentLength(HttpHeaders.java:963)
at org.springframework.http.codec.EncoderHttpMessageWriter.lambda$write$1(EncoderHttpMessageWriter.java:135)
Question: can an @ExceptionHandler be written so, that it
- either does NOT handle this particular error type (
AbortedException) - or does NOT return any value
- or otherwise signals that no response needs to be written in some cases
while being able to handler other Exception.class-type exceptions normally (by returning a body of a particular type)
?