I've updated TestAsyncTlsHandshakeTimeout to reproduce this bug.
Specifically, see the two test cases that use FORCE_HTTP_2 (they will be
marked as ignored in the test report, but they still run).

On Wed, Jan 21, 2026 at 3:13 PM Ryan Schmitt <[email protected]> wrote:

> I got a report today that the `ioReactorExceptionCallback` is firing due
> to a socket timeout:
>
> java.net.SocketTimeoutException: 2500 MILLISECONDS
> at
> org.apache.hc.core5.io.SocketTimeoutExceptionFactory.create(SocketTimeoutExceptionFactory.java:50)
> at
> org.apache.hc.core5.reactor.ssl.SSLIOSession$1.timeout(SSLIOSession.java:223)
> at
> org.apache.hc.core5.reactor.InternalDataChannel.onTimeout(InternalDataChannel.java:170)
> at
> org.apache.hc.core5.reactor.InternalChannel.checkTimeout(InternalChannel.java:67)
> at
> org.apache.hc.core5.reactor.SingleCoreIOReactor.checkTimeout(SingleCoreIOReactor.java:239)
> at
> org.apache.hc.core5.reactor.SingleCoreIOReactor.validateActiveChannels(SingleCoreIOReactor.java:166)
> at
> org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:128)
> at
> org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:92)
> at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44)
> at java.base/java.lang.Thread.run(Thread.java:840)
>
> Based on the code and the stack trace, 2500 milliseconds is actually the
> connection timeout and thus the TLS handshake timeout. This is reproducible
> in TestAsyncTlsHandshakeTimeout by setting `HttpVersionPolicy.FORCE_HTTP_2`
> (but _not_ `NEGOTIATE`). I traced this change in behavior back to the
> following commit:
>
>
> https://github.com/apache/httpcomponents-core/commit/be9902826576413c694c59cc582fc38db8aeb772
>
> This is a regression, as the contract for
> `setIoReactorExceptionCallback()` is that it sets a callback for exceptions
> that propagate all the way through the IOReactor *and kill the client*. The
> default behavior (cf. LoggingExceptionCallback) is to log an ERROR, which
> is bad enough, but in our case we supply a custom callback that logs a
> FATAL, which then triggers alarms and stuff.
>
> How should we address this? What types of exceptions were intended to be
> reported by be9902826? We probably (1) want to use a different exception
> callback for these exceptions and (2) want to fire the callback only for
> unexpected (internal) exceptions and not things like timeouts. It's also
> possible that this exception callback should fire when
> `HttpVersionPolicy.NEGOTIATE` is used; it currently doesn't, which may also
> be a bug.
>

Reply via email to