apache/druid · warning
Thread interrupted while adding to queue
Error message
Thread interrupted while adding to queue
What it means
In SequenceInputStreamResponseHandler.handleChunk, each downloaded chunk is opened as a stream and put into the queue with queue.put(), which blocks when the queue is full. If the producer thread is interrupted while blocked on put(), the code logs a warning, re-interrupts, and wraps the InterruptedException in a RuntimeException. This signals the response processing was cancelled mid-chunk.
Solutions
- Determine who interrupted the producer thread; usually a legitimate cancellation (client disconnect, query cancel)
- Ensure consumers read or close the SequenceInputStream promptly to keep the queue draining
- Avoid Future.cancel(true)/Thread.interrupt() on the HTTP response-processing thread except for real cancellations
- Check for timeouts configured shorter than the download duration that trigger interrupts
Example fix
// before: abandoning the stream mid-download
httpClient.go(request, handler).get(); // no timeout/cancel management
// after: register cancellation and close on timeout
ListenableFuture<InputStream> f = httpClient.go(request, handler);
try {
f.get(timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException te) {
f.cancel(false); // avoid interrupting producer mid-put unless cancelling
throw te;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the consumer is alive before streaming large responses
if (consumerClosed) {
responseFuture.cancel(false); // stop download without interrupting producer
return;
} Try / catch
try {
queue.put(chunkStream);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new CancellationException("Response processing cancelled");
} Prevention
- Always consume or close the SequenceInputStream so the bounded queue drains
- Use cancel(false) when you want the download to wind down without interrupts
- Match HTTP client timeouts to expected response duration to avoid timeout-driven interrupts
- Watch for consumer crashes that leave the queue full and the producer blocked
When it happens
Trigger: The thread running handleChunk is interrupted while blocked on queue.put() because the consumer stopped reading (queue full) and someone interrupted the producer, e.g. request cancellation or client disconnect detected mid-response.
Common situations: Downstream consumer crashed/closed while the HTTP client continued downloading, filling the bounded queue; query cancellation; container/executor shutdown during a long streaming download.
Related errors
- Thread interrupted while taking from queue
- Cleaning up idle connections is a bad idea. If your…
- Failed to apply webClientOptions to WebClientOptions. Check…
- Failed to close OpenLineage HTTP client
- Failed to configure TLS for OpenLineage HTTP transport
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/152609cd6ebc0dea.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/java/util/http/client/response/SequenceInputStreamResponseHandler.java:121
public ClientResponse<InputStream> handleChunk(
ClientResponse<InputStream> clientResponse,
HttpChunk chunk,
long chunkNum
)
{
final ChannelBuffer channelBuffer = chunk.getContent();
final int bytes = channelBuffer.readableBytes();
if (bytes > 0) {
try (ChannelBufferInputStream channelStream = new ChannelBufferInputStream(channelBuffer)) {
queue.put(channelStream);
// Queue.size() can be expensive in some implementations, but LinkedBlockingQueue.size is just an AtomicLong
log.debug("Added stream. Queue length %d", queue.size());
}
catch (IOException e) {
throw new RuntimeException(e);
}
catch (InterruptedException e) {
log.warn(e, "Thread interrupted while adding to queue");
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
byteCount.addAndGet(bytes);
} else {
log.debug("Skipping zero length chunk");
}
return clientResponse;
}
@Override
public ClientResponse<InputStream> done(ClientResponse<InputStream> clientResponse)
{
synchronized (done) {
try {
// An empty byte array is put at the end to give the SequenceInputStream.close() as something to close out
// after done is set to true, regardless of the rest of the stream's state.
queue.put(ByteSource.empty().openStream());View on GitHub (pinned to 9b90983fd2)