apache/druid · error · QueryTimeoutException

Query [%s] timed out

Error message

Query [%s] timed out

What it means

waitForFutureCompletion waits on the merging query runner's futures for the configured query timeout. On QueryTimeoutException or TimeoutException it cancels the outstanding per-segment futures and throws QueryTimeoutException('Query [id] timed out'), surfacing the broker/timeout chain to the caller.

Source

Thrown at processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/GroupByMergingQueryRunner.java:399

      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)

Solutions

  1. Raise the query timeout (timeout field in the query context / druid.query.defaultTimeout)
  2. Optimize the query: narrow intervals, add filters, reduce dimensions/aggregators, enable query caching
  3. Scale historicals (more cores/memory) or raise druid.processing.numThreads
  4. Check for skewed/slow segments and broker queue wait times in metrics (query/time, query/wait/time)
  5. Split the query into smaller time chunks and merge client-side

Example fix

// before
{"queryType":"groupBy", "intervals":["2010/2026"], ...} // exceeds default timeout
// after
{"queryType":"groupBy", "intervals":["2025/2026"], "context":{"timeout":"1800000"}, ...} // narrower range + explicit timeout
Defensive patterns

Strategy: retry

Validate before calling

long estMillis = estimateScanTime(query); // compare against configured timeout before submitting
if (estMillis > timeoutMs) { narrowIntervalsOrRaiseTimeout(); }

Try / catch

try { runQuery(query); } catch (QueryTimeoutException e) { if (e.getMessage().endsWith("timed out")) { retryWithLargerTimeout(narrow(query)); } else { throw e; } }

Prevention

When it happens

Trigger: A groupBy query's per-segment or overall futures do not complete within the configured timeout (query.getConfig().getTimeout() / PrioritizedExecutorTask queue wait), so waitForFutureCompletion (invoked from apply or make) cancels and throws.

Common situations: Heavy groupBy queries with huge cardinality; undersized processing thread pools; slow historicals (disk, GC); default 5-minute timeout exceeded; timeouts on large multi-interval scans.

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/1f50f25a78024a9c. Report an issue: GitHub.