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

  1. Remove non-sortable columns from the ORDER BY / cluster key in the SQL query.
  2. Cast or extract a primitive (string/number) from complex values before sorting, e.g. ORDER BY JSON_VALUE(col, '$.field').
  3. 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

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


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