apache/druid · error · RuntimeException

Failed to offer result to output queue

Error message

Failed to offer result to output queue

What it means

In ParallelMergeCombiningSequence, the ResultBatch consumer thread blocks offering results to the output queue via ForkJoinPool.managedBlock(). If the thread is interrupted while blocked, it wraps the InterruptedException in a RuntimeException with this message, abandoning the result batch.

Source

Thrown at processing/src/main/java/org/apache/druid/java/util/common/guava/ParallelMergeCombiningSequence.java:867

      }
      return success;
    }

    @Override
    public boolean isReleasable()
    {
      return item == null;
    }

    public void offer(ResultBatch<E> item)
    {
      try {
        this.item = item;
        ForkJoinPool.managedBlock(this);
      }
      catch (InterruptedException e) {
        this.item = null;
        throw new RuntimeException("Failed to offer result to output queue", e);
      }
    }

    public void tryOfferTerminal()
    {
      this.queue.offer(ResultBatch.terminal());
    }
  }

  /**
   * Holder object for an ordered batch of results from a sequence. Batching the results vastly reduces the amount of
   * blocking that is needed to move results between stages of {@link MergeCombineAction} done in parallel, allowing
   * the fork join tasks to focus on doing actual work instead of dealing with managed blocking.
   */
  static class ResultBatch<E>
  {
    static <T> ResultBatch<T> terminal()
    {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Inspect the cause chain for the original InterruptedException to confirm cancellation source
  2. Treat this as expected during query cancellation; retry only if the interruption was spurious
  3. Ensure downstream consumers drain the output queue promptly to avoid blocking offers

Example fix

// before
Sequence<ResultRow> seq = ParallelMergeCombiningSequence.create(...); // interrupted mid-merge
// after
try (QueryLifecycle ql = ...) { ... } catch (RuntimeException e) {
  if (e.getCause() instanceof InterruptedException) { /* cancellation path */ }
  throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try { /* consume merge sequence */ } catch (RuntimeException e) {
  if (e.getCause() instanceof InterruptedException) { Thread.currentThread().interrupt(); /* treat as cancellation */ }
  else throw e;
}

Prevention

When it happens

Trigger: Query cancellation or shutdown interrupting the worker thread while it waits to offer a ResultBatch to a full output queue during parallel merge/combine of sequences.

Common situations: User cancels a long-running SQL/native query; server shutdown or timeout cancels in-flight parallel merges; downstream consumer stalls causing the output queue to fill.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/022454756cea9e33. Report an issue: GitHub.