apache/druid · warning
Query interrupted, cancelling pending results for query
Error message
Query interrupted, cancelling pending results for query [%s]
What it means
GroupByMergingQueryRunner.waitForFutureCompletion blocks on per-segment group-by futures and, on InterruptedException or CancellationException, cancels all outstanding futures and throws QueryInterruptedException after logging the query id. Like the chained runner, this is the cancellation/interruption cleanup path for the group-by v2 merging stage.
Solutions
- If the query was cancelled intentionally, this log is expected — no action needed
- Trace the cancellation source in broker logs (client disconnect vs explicit DELETE on /druid/v2)
- Tune group-by performance (groupBy maxOnDiskStorage, buffer sizes, numThreads) so queries finish before client-side timeouts trigger cancellation
- Set client read timeouts larger than query context timeout so the server isn't interrupted mid-merge
Example fix
// before: client timeout shorter than query timeout
// curl --max-time 30 ... while context timeout is 300s
// after: align timeouts
// curl --max-time 300 ... and {"context":{"timeout":300000}} Defensive patterns
Strategy: try-catch
Validate before calling
// Bound query cost before submitting: check the interval and granularity are narrow
if (interval.toDurationMillis() > maxAllowedScanMillis) {
throw new IllegalArgumentException("Query interval too large for group-by");
} Try / catch
try {
result = runner.run(queryPlus, responseContext).toList();
} catch (QueryInterruptedException e) {
if (e.getCause() instanceof CancellationException || e.getCause() instanceof InterruptedException) {
// treat as cancellation, release partial results
} else {
throw e;
}
} Prevention
- Set client read timeouts >= query context timeout to avoid interrupting the merge phase
- Tune group-by buffers (druid.query.groupBy.maxOnDiskStorage, buffer-group size) so merges complete promptly
- Cancel heavy queries explicitly rather than letting client disconnects race completion
- Ensure brokers are not restarted mid-query (maintenance windows)
When it happens
Trigger: While waitForFutureCompletion waits on futures: the query is cancelled (cancellation endpoint or client disconnect propagation), or the merging thread is interrupted (broker shutdown, interrupt-based timeout).
Common situations: User cancels a heavy group-by query; broker or historical shutdown during merge; client timeout closes the HTTP connection, propagating cancellation to the merge phase.
Related errors
- Query interrupted, cancelling pending results for query
- Cannot order by a non-numeric aggregator
- Invalid maxLoadFactor
- Invalid maxLoadFactor
- Unknown column in order clause
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/57551870f657db3c.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/GroupByMergingQueryRunner.java:392
if (queryWatcher != null) {
queryWatcher.registerQueryFuture(query, future);
}
if (hasTimeout && timeout <= 0) {
throw new QueryTimeoutException();
}
final List<AggregateResult> results = hasTimeout ? future.get(timeout, TimeUnit.MILLISECONDS) : future.get();
for (AggregateResult result : results) {
if (!result.isOk()) {
GuavaUtils.cancelAll(true, future, futures);
throw new ResourceLimitExceededException(result.getReason());
}
}
}
catch (InterruptedException | CancellationException e) {
log.noStackTrace().warn(e, "Query interrupted, cancelling pending results for query [%s]", query.getId());
GuavaUtils.cancelAll(true, future, futures);
throw new QueryInterruptedException(e);
}
catch (QueryTimeoutException | TimeoutException e) {
log.noStackTrace().warn(e, "Query timeout, cancelling pending results for query [%s]", query.getId());
GuavaUtils.cancelAll(true, future, futures);
throw new QueryTimeoutException(StringUtils.nonStrictFormat("Query [%s] timed out", query.getId()));
}
catch (ExecutionException e) {
log.noStackTrace().warn(e, "Query error, cancelling pending results for query [%s]", query.getId());
GuavaUtils.cancelAll(true, future, futures);
Throwable cause = e.getCause();
// Nested per-segment future timeout
if (cause instanceof TimeoutException) {
throw new QueryTimeoutException(StringUtils.nonStrictFormat("Query timeout, cancelling pending results for query [%s]. Per-segment timeout exceeded.", query.getId()));
}
throw new RuntimeException(e);
}View on GitHub (pinned to 9b90983fd2)