apache/druid · error · UnsupportedOperationException (UOE)

Time-ordering on scan queries is only supported for queries…

Error message

Time-ordering on scan queries is only supported for queries with segment specs of type MultipleSpecificSegmentSpec or SpecificSegmentSpec...a [%s] was received instead.

What it means

Time-ordered scans need an explicit per-segment interval ordering, which only MultipleSpecificSegmentSpec and SpecificSegmentSpec provide. Any other query spec (e.g. AllSegmentsQuerySpec or MultipleIntervalSegmentSpec) cannot be ordered deterministically and is rejected with this UOE.

Solutions

  1. Remove the time-ordering (order=null / drop ORDER BY on the scan) if per-segment specs cannot be used.
  2. Target specific segments via SpecificSegmentSpec or MultipleSpecificSegmentSpec when ordering is required.
  3. Ensure broker/server versions are consistent so specific-segment specs survive query routing.

Example fix

// before
new ScanQuery(DataSegmentDescriptor.of(segment), ..., Order.DESCENDING); // with AllSegmentsQuerySpec
// after: use a specific-segment spec
descriptors.forEach(d -> query.withQuerySegmentSpec(new MultipleSpecificSegmentSpec(descriptors)));
Defensive patterns

Strategy: validation

Validate before calling

if (query.getOrdering() != null
    && !(query.getQuerySegmentSpec() instanceof MultipleSpecificSegmentSpec)
    && !(query.getQuerySegmentSpec() instanceof SpecificSegmentSpec)) {
  throw new IllegalArgumentException("time-ordering requires specific segment specs");
}

Type guard

boolean specSupportsOrdering(QuerySegmentSpec spec) {
  return spec instanceof MultipleSpecificSegmentSpec || spec instanceof SpecificSegmentSpec;
}

Try / catch

try {
  results = runner.run(QueryPlus.wrap(query), ctx).toList();
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("Time-ordering on scan queries")) { /* drop ordering or switch spec */ }
  else throw e;
}

Prevention

When it happens

Trigger: Running a ScanQuery with resultOrdering set while its query spec is MultipleIntervalSegmentSpec or AllSegmentsQuerySpec — typically when a client sets order=descending on a query that also uses broad interval-based segment selection.

Common situations: SQL scan queries with ORDER BY __time DESC planned against interval specs; custom tools constructing ScanQuery with default specs plus ordering; older clients whose broker collapsed specific specs into interval specs.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/scan/ScanQueryRunnerFactory.java:296

  @VisibleForTesting
  List<Interval> getIntervalsFromSpecificQuerySpec(QuerySegmentSpec spec)
  {
    // Query segment spec must be an instance of MultipleSpecificSegmentSpec or SpecificSegmentSpec because
    // segment descriptors need to be present for a 1:1 matching of intervals with query runners.
    // The other types of segment spec condense the intervals (i.e. merge neighbouring intervals), eliminating
    // the 1:1 relationship between intervals and query runners.
    List<Interval> descriptorsOrdered;

    if (spec instanceof MultipleSpecificSegmentSpec) {
      // Ascending time order for both descriptors and query runners by default
      descriptorsOrdered = ((MultipleSpecificSegmentSpec) spec).getDescriptors()
                                                               .stream()
                                                               .map(SegmentDescriptor::getInterval)
                                                               .collect(Collectors.toList());
    } else if (spec instanceof SpecificSegmentSpec) {
      descriptorsOrdered = Collections.singletonList(((SpecificSegmentSpec) spec).getDescriptor().getInterval());
    } else {
      throw new UOE(
          "Time-ordering on scan queries is only supported for queries with segment specs "
          + "of type MultipleSpecificSegmentSpec or SpecificSegmentSpec...a [%s] was received instead.",
          spec.getClass().getSimpleName()
      );
    }
    return descriptorsOrdered;
  }

  @VisibleForTesting
  Sequence<ScanResultValue> nWayMergeAndLimit(
      List<List<QueryRunner<ScanResultValue>>> groupedRunners,
      QueryPlus<ScanResultValue> queryPlus,
      ResponseContext responseContext
  )
  {
    // Starting from the innermost Sequences.map:
    // (1) Deaggregate each ScanResultValue returned by the query runners
    // (2) Combine the deaggregated ScanResultValues into a single sequence

View on GitHub (pinned to 9b90983fd2)