apache/druid · error · IllegalStateException
Pre-sorted data required, rows
Error message
Pre-sorted data required, rows[%s] and [%s] were not in order
What it means
DefaultGroupPartitioner.computeGroupings assigns group IDs by scanning consecutive rows and requires rows pre-sorted by the grouping columns. If it detects two adjacent rows where the previous row compares greater than the current one (comparison > 0) while their group values are equal, the pre-sort invariant is violated and Druid throws ISE.
Solutions
- Ensure the input is sorted by the grouping columns before calling computeGroupings
- Insert/repair an upstream sort stage
- Verify the row accessor's comparison is consistent with the actual sort order used
Defensive patterns
Strategy: validation
Validate before calling
// verify adjacent rows are ordered before grouping
for (int i = 1; i < accessor.numRows(); i++) {
if (accessor.compareRows(i - 1, i) > 0) {
throw new IllegalStateException("rows not pre-sorted at " + i);
}
} Try / catch
try {
groupings = partitioner.computeGroupings(accessor);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Pre-sorted data required")) {
accessor = sort(accessor);
groupings = partitioner.computeGroupings(accessor);
} else throw e;
} Prevention
- Always sort input by grouping columns before group-partitioning
- Keep the sort operator's ordering consistent with the accessor's comparator
When it happens
Trigger: computeGroupings is called on data whose accessor.compareRows(i-1, i) returns a positive value for adjacent rows, i.e. input rows are out of order relative to the grouping keys.
Common situations: A downstream/window operator consuming unsorted input; a sort stage removed or broken upstream; custom adapter feeding rows in arbitrary order.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- can't reschedule fetch records runnable, recordsResult is…
- Error! More than one matching entry
- Expected sink to be no longer writable before mergeAndPush…
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/7c39acd4fadfb87e.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/rowsandcols/semantic/DefaultGroupPartitioner.java:64
for (String column : columns) {
final Column theCol = rac.findColumn(column);
if (theCol == null) {
// The column doesn't exist. In this case, we assume it's always the same value: null. If it's always
// the same, then it doesn't impact grouping at all and can be entirely skipped.
continue;
}
final ColumnAccessor accessor = theCol.toAccessor();
int currGroup = 0;
int prevGroupVal = 0;
for (int i = 1; i < retVal.length; ++i) {
if (retVal[i] == prevGroupVal) {
int comparison = accessor.compareRows(i - 1, i);
if (comparison == 0) {
retVal[i] = currGroup;
continue;
} else if (comparison > 0) { // "greater than"
throw new ISE("Pre-sorted data required, rows[%s] and [%s] were not in order", i - 1, i);
} // the 3rd condition ("less than") means create a new group, so let it fall through
}
// We have a new group, so walk things forward.
prevGroupVal = retVal[i];
retVal[i] = ++currGroup;
}
}
return retVal;
}
}
View on GitHub (pinned to 9b90983fd2)