apache/druid · error · IllegalStateException
Cannot create comparator for array type
Error message
Cannot create comparator for array type %s.
What it means
DefaultLimitSpec builds Comparators to apply a topN-style limit/order-by on group-by results. Comparator construction only supports scalar column types plus string-array and primitive-array types (compared via DimensionHandlerUtils.coerceToStringArray); for any other array type (e.g. COMPLEX arrays or otherwise unsupported array dimensions) it throws this ISE rather than producing a wrong ordering.
Solutions
- Change the query to order by a scalar column, or project/flatten the array into a scalar before applying the limit spec
- Remove or restrict the OrderByColumnSpec on the array column and sort client-side after the query returns
- If support is genuinely needed, extend dimensionOrdering to add a comparator branch for the missing array type and file an issue upstream
Example fix
// before
OrderByColumnSpec spec = OrderByColumnSpec.ascending("arrDim"); // arrDim is a complex array
new DefaultLimitSpec(ImmutableList.of(spec), 100)
// after
OrderByColumnSpec spec = OrderByColumnSpec.ascending("scalarDim"); // order by scalar instead Defensive patterns
Strategy: validation
Validate before calling
ColumnCapabilities caps = rowSignature.getColumnCapabilities(colName);
if (caps != null && caps.getType().isArray() &&
!(caps.getType() == ColumnType.STRING_ARRAY || caps.getType() == ColumnType.LONG_ARRAY || caps.getType() == ColumnType.DOUBLE_ARRAY)) {
throw new IllegalArgumentException("Cannot order by array column of type " + caps.getType());
} Type guard
boolean isOrderableArray(ColumnType t) {
return t.isArray()
&& (ColumnType.STRING_ARRAY.equals(t) || ColumnType.LONG_ARRAY.equals(t) || ColumnType.DOUBLE_ARRAY.equals(t));
} Try / catch
try {
return limitSpec.build(...) ;
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Cannot create comparator")) {
// fall back to client-side sort or scalar projection
} else throw e;
} Prevention
- Only add OrderByColumnSpec entries on scalar columns or supported array types (string/long/double arrays)
- Check the row signature's column capabilities before attaching a DefaultLimitSpec
- Sort array columns client-side after retrieval instead of server-side
When it happens
Trigger: Calling makeComparator/dimensionOrdering with an OrderByColumnSpec whose column has an array ColumnType not in the supported set (e.g. a complex or long/double array dimension ordering) while applying a DefaultLimitSpec to group-by results.
Common situations: Ordering group-by output by an array-typed dimension such as a filtered/transformed array column, or after upgrading Druid and introducing array-typed columns into queries that previously used scalar dimensions with limit specs.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot handle column
- Cannot handle column
- Cannot handle column
- Cannot handle column
- Cannot handle column
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/a82412b1f518d6f5.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/groupby/orderby/DefaultLimitSpec.java:475
};
} else if (columnType.getElementType().equals(ColumnType.STRING)) {
arrayComparator = (o1, o2) -> {
if (stringComparator == null
|| StringComparators.NATURAL.equals(stringComparator)
|| StringComparators.LEXICOGRAPHIC.equals(stringComparator)) {
return columnType.getNullableStrategy().compare(
DimensionHandlerUtils.coerceToStringArray(o1),
DimensionHandlerUtils.coerceToStringArray(o2)
);
}
return new DimensionComparisonUtils.ArrayComparator<>(stringComparator)
.compare(
DimensionHandlerUtils.coerceToStringArray(o1),
DimensionHandlerUtils.coerceToStringArray(o2)
);
};
} else {
throw new ISE("Cannot create comparator for array type %s.", columnType.toString());
}
}
final Comparator comparatorToUse;
if (arrayComparator != null) {
comparatorToUse = arrayComparator;
} else {
comparatorToUse = DimensionComparisonUtils.isNaturalComparator(columnType.getType(), stringComparator)
? columnType.getNullableStrategy()
: stringComparator;
}
return Ordering.from(
Comparator.comparing(
(ResultRow row) -> {
if (columnType.isArray()) {
// Arrays have a specialized comparator, that applies the ordering per element. That will handle the casting
// and the comparison
return row.get(column);View on GitHub (pinned to 9b90983fd2)