Potential bug in HttpClientImpl: Thread pool rejection causes permanent client failure

Daniel Fuchs daniel.fuchs at oracle.com
Wed Jun 18 17:42:27 UTC 2025


Hi David,

As a general rule, the client doesn't expect tasks to
be rejected by the executor. Tasks need to be executed,
one way or another, for the client to work as expected.
Executing in the current thread is often not an option
as it may lead to deadlocks.
So if we get a RejectedTaskExection, we shutdown the
client, as there's not much else we can do.

We have some contengency measure for shutdown in case of
RejectedTaskException that will temporarily execute rejected
tasks in the FJP instead when the executor rejects a task,
but this is only a best effort whose only goal is to make
it possible to complete the shutdown, and wakeup any calling
code that may be waiting on send or completable futures returned
by sendAsync.

best regards,

-- daniel

On 18/06/2025 17:24, David Nadeau wrote:
> When overriding the HttpClient executor with a custom ThreadPoolExecutor 
> that uses the default RejectedExecutionHandler.AbortPolicy, the Java 
> HTTP client (java.net.http.HttpClient) becomes permanently unusable if 
> the delegate executor rejects a task.
> 
> This creates a situation where transient thread pool saturation results 
> in a non-recoverable client failure.
> 
> Reproduction of the issue:
> 1. The task rejection triggers a call to the error handler (onSubmitFailure)
> 2. This calls selmgr.abort(failure) with the rejection exception
> 3. SelectorManager.abort() sets this.closed = true permanently
> 4. All subsequent HTTP operations fail with "IOException: selector 
> manager closed"
> 
> The client does not recover from this state.
> 
> I was able to avoid this by using the DiscardPolicy instead of the 
> AbortPolicy. However, this behavior was quite a surprise to debug. Is 
> this behavior intentional, or does it make sense for the HttpClient to 
> treat task rejection as a recoverable error?



More information about the net-dev mailing list