apache/druid · error · UnsupportedOperationException (UOE)
Limit of %,d rows not supported for priority queue strategy…
Error message
Limit of %,d rows not supported for priority queue strategy of time-ordering scan results
What it means
When a scan query uses resultOrdering (time-ordering), rows are buffered in an in-memory priority queue, so the scanRows limit must fit an int. A limit above Integer.MAX_VALUE cannot be allocated and is rejected with this UOE.
Solutions
- Lower the scan query limit (scanRows / SQL LIMIT) to at most Integer.MAX_VALUE, ideally a realistic page size.
- If you truly need unbounded results, remove the time-ordering ('descending' ordering) so the priority-queue strategy is not used and pagination via scanRowsOffset applies.
- For large exports, iterate with ordered batches (limit + offset) instead of one giant ordered scan.
Example fix
// before ScanQuery q = new ScanQueryBuilder().order(Order.DESCENDING).limit(Long.MAX_VALUE).build(); // after ScanQuery q = new ScanQueryBuilder().order(Order.DESCENDING).limit(1_000_000).build();
Defensive patterns
Strategy: validation
Validate before calling
if (query.getOrdering() != null && query.getScanRowsLimit() > Integer.MAX_VALUE) {
throw new IllegalArgumentException("scanRows limit too large for time-ordered scan");
} Type guard
boolean limitFitsPriorityQueue(ScanQuery q) { return q.getScanRowsLimit() <= Integer.MAX_VALUE; } Try / catch
try {
results = runner.run(QueryPlus.wrap(query), ctx).toList();
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("not supported for priority queue")) { query = query.withLimit(Integer.MAX_VALUE); }
else throw e;
} Prevention
- Cap scanRows limits at Integer.MAX_VALUE.
- Use batching (limit+offset) for large ordered exports.
- Only enable ordering when a bounded limit is set.
When it happens
Trigger: Running a ScanQuery with getOrdering() set (descending time-ordering) and scanRowsLimit > 2147483647 (e.g. Long.MAX_VALUE, often from a default/unbounded limit configured for a non-time-ordered scan).
Common situations: Setting scanRowsLimit to Long.MAX_VALUE or a huge default in client code/SQL (LIMIT-less scan defaults) while also enabling ordering: 'descending' in SQL scan queries.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Cannot apply limit[ ] with offset[ ] due to overflow
- Cannot execute query with orderBy
- Cannot provide 'order' incompatible with 'orderBy'
- Column [ ] from 'orderBy' must also appear in 'columns'.
- Got a [ ] which isn't a
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/82fcc396916c1805.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/scan/ScanQueryRunnerFactory.java:222
}
};
}
/**
* Returns a sorted and limited copy of the provided {@param inputSequence}. Materializes the full sequence
* in memory before returning it. The amount of memory use is limited by the limit of the {@param scanQuery}.
*/
@VisibleForTesting
Sequence<ScanResultValue> stableLimitingSort(
Sequence<ScanResultValue> inputSequence,
ScanQuery scanQuery,
List<Interval> intervalsOrdered
) throws IOException
{
Comparator<ScanResultValue> comparator = scanQuery.getResultOrdering();
if (scanQuery.getScanRowsLimit() > Integer.MAX_VALUE) {
throw new UOE(
"Limit of %,d rows not supported for priority queue strategy of time-ordering scan results",
scanQuery.getScanRowsLimit()
);
}
// Converting the limit from long to int could theoretically throw an ArithmeticException but this branch
// only runs if limit < MAX_LIMIT_FOR_IN_MEMORY_TIME_ORDERING (which should be < Integer.MAX_VALUE)
int limit = Math.toIntExact(scanQuery.getScanRowsLimit());
final StableLimitingSorter<ScanResultValue> sorter = new StableLimitingSorter<>(comparator, limit);
Yielder<ScanResultValue> yielder = Yielders.each(inputSequence);
try {
boolean doneScanning = yielder.isDone();
// We need to scan limit elements and anything else in the last segment
int numRowsScanned = 0;
Interval finalInterval = null;View on GitHub (pinned to 9b90983fd2)