jetty.project icon indicating copy to clipboard operation
jetty.project copied to clipboard

OutputStreamContentSource.AsyncOutputStream rethrows already thrown exception

Open hwanders opened this issue 1 year ago • 2 comments

Jetty version(s) 12.0.11

Jetty Environment core

Java version/vendor (use: java -version) OpenJDK 17.0.10

OS type/version Windows

Description Executing a JettyClientHttpRequest throws an IllegalArgumentException with message Self-suppression not permitted if a SocketTimeoutException occurs when writing the response.

This is similar to #11736.

Reason

  1. In JettyClientHttpRequest.executeInternal an OutputStream is constructed from requestContent.getOutputStream() and the body is written to it
  2. That stream is of type OutputStreamContentSource.AsyncOutputStream
  3. During writing of the body, a flush might be performed triggering AsyncOutputStream.write
  4. The write delegates to AsyncOutput.write and the SocketTimeoutException may arise (let's assume that)
  5. That exception is caught and written to persistentFailure and thrown (and rethrown) in AsyncOutputStream.write.
  6. JettyClientHttpRequest.executeInternal's try-with-resources-block notices the exception and tries to close the output stream
  7. Closing the stream again causes a flush which repeats the persistentFailure
  8. Java notices that the try-with-resources block's finally-block throws and wants to suppress the original exception (from the write) - but it's exactly the same exception again, which leads to the IllegalArgumentException

How to reproduce? Try to send a large enough request to an unresponsive host causing an intermediate flush.

hwanders avatar Jul 11 '24 11:07 hwanders

This happens in my Spring Boot application using a RestTemplate.

To temporarily avoid the error, I've created a ClientHttpRequestInterceptor which catches IllegalArgumentException if it contains the message Self-suppression not permitted and in this case rethrows its cause (wrapped in an IOException if that's not the case already) - otherwise rethrows the exception unmodified.

hwanders avatar Jul 11 '24 11:07 hwanders

See also https://github.com/spring-projects/spring-framework/issues/33375 where another popular use case is reported with a repro.

sdeleuze avatar Aug 13 '24 14:08 sdeleuze

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Aug 23 '25 00:08 github-actions[bot]

Similar issue to #11736, with a similar solution.

For the record, here is how try-with-resources is specified: https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.20.3.1

sbordet avatar Aug 24 '25 17:08 sbordet

Fixed in #13514.

sbordet avatar Aug 28 '25 16:08 sbordet