apache/druid · error · IllegalArgumentException
ClusterBy key must be sortable
Error message
ClusterBy key must be sortable
What it means
This shuffle spec orders output globally by the clusterBy key, so the key must support total ordering (sortable()). If the key columns' types cannot be sorted (e.g. complex/nested types without comparators), the constructor throws IAE.
Source
Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/kernel/GlobalSortMaxCountShuffleSpec.java:73
@JsonProperty("adjustable") final boolean adjustable
)
{
this.clusterBy = Preconditions.checkNotNull(clusterBy, "clusterBy");
this.maxPartitions = maxPartitions;
this.aggregate = aggregate;
this.limitHint = limitHint == null ? UNLIMITED : limitHint;
this.adjustable = adjustable;
if (maxPartitions < 1) {
throw new IAE("Partition count must be at least 1");
}
if (adjustable && maxPartitions != 1) {
throw new IAE("Partition count must be 1 when adjustable is true, but was [%d]", maxPartitions);
}
if (!clusterBy.sortable()) {
throw new IAE("ClusterBy key must be sortable");
}
if (clusterBy.getBucketByCount() > 0) {
// Only GlobalSortTargetSizeShuffleSpec supports bucket-by.
throw new IAE("Cannot bucket with %s partitioning", TYPE);
}
}
public GlobalSortMaxCountShuffleSpec(
final ClusterBy clusterBy,
final int maxPartitions,
final boolean aggregate,
final Long limitHint
)
{
this(clusterBy, maxPartitions, aggregate, limitHint, false);
}
View on GitHub (pinned to 9b90983fd2)
Solutions
- Remove non-sortable columns from the ORDER BY / cluster key in the SQL query.
- Cast or extract a primitive (string/number) from complex values before sorting, e.g. ORDER BY JSON_VALUE(col, '$.field').
- Choose a shuffle spec type that supports the key if global sorting is not required.
Example fix
// before SELECT ... ORDER BY complexCol // after SELECT ... ORDER BY JSON_VALUE(complexCol, '$.field')
Defensive patterns
Strategy: validation
Validate before calling
if (!clusterBy.sortable()) {
throw new IllegalArgumentException("ClusterBy key must be sortable before using maxCountSorting");
} Try / catch
try {
spec = new GlobalSortMaxCountShuffleSpec(clusterBy, ...);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().equals("ClusterBy key must be sortable")) {
// fall back to a non-globally-sorted shuffle spec or rewrite the key
} else {
throw e;
}
} Prevention
- Restrict ORDER BY keys to primitive sortable types in MSQ queries.
- Use JSON_VALUE / casting to extract sortable scalars from complex columns.
- Check column types in the ingestion schema before planning global sorts.
When it happens
Trigger: Constructing the spec with a ClusterBy whose key contains columns of non-sortable types - typically COMPLEX or array/nested types without an ordering, coming from a query whose ORDER BY or grouping key includes such columns.
Common situations: ORDER BY on complex columns (e.g. nested JSON) in an MSQ insert/replace; sorting on array-typed expressions when the sort spec doesn't support them; schema changes making previously sortable columns complex.
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
- Partition count must be at least 1
- Partition count must be 1 when adjustable is true, but was [
- Cannot have empty worker set
- Can not supply empty segments as input, please use either nu
- Cannot bucket with %s partitioning
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/71c790b11c338d6a.
Report an issue: GitHub.