apache/druid · error · IllegalArgumentException

Partition count must be 1 when adjustable is true, but was [

Error message

Partition count must be 1 when adjustable is true, but was [%d]

What it means

HashShuffleSpec with adjustable=true means the controller may re-shard at runtime starting from a single partition, so the constructor requires numPartitions == 1. Passing adjustable=true with any other partition count violates that contract and throws IAE. Adjustable hash shuffles must seed with exactly one partition.

Source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/kernel/HashShuffleSpec.java:50

  public static final String TYPE = "hash";

  private final ClusterBy clusterBy;
  private final int numPartitions;
  private final boolean adjustable;

  @JsonCreator
  public HashShuffleSpec(
      @JsonProperty("clusterBy") final ClusterBy clusterBy,
      @JsonProperty("partitions") final int numPartitions,
      @JsonProperty("adjustable") final boolean adjustable
  )
  {
    this.clusterBy = clusterBy;
    this.numPartitions = numPartitions;
    this.adjustable = adjustable;

    if (adjustable && numPartitions != 1) {
      throw new IAE("Partition count must be 1 when adjustable is true, but was [%d]", numPartitions);
    }

    if (clusterBy.getBucketByCount() > 0) {
      // Only GlobalSortTargetSizeShuffleSpec supports bucket-by.
      throw new IAE("Cannot bucket with %s partitioning (clusterBy = %s)", TYPE, clusterBy);
    }
  }

  @Override
  public ShuffleKind kind()
  {
    return clusterBy.sortable() && !clusterBy.isEmpty() ? ShuffleKind.HASH_LOCAL_SORT : ShuffleKind.HASH;
  }

  @Override
  @JsonProperty
  public ClusterBy clusterBy()
  {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Set numPartitions to 1 when adjustable is true, letting the controller grow partitions dynamically
  2. Set adjustable to false if a fixed numPartitions > 1 is genuinely required
  3. Audit the call site (ShuffleSpecFactory.create) so the partition count passed for adjustable shuffles is always 1

Example fix

// before
new HashShuffleSpec(clusterBy, 4, true);
// after
new HashShuffleSpec(clusterBy, 1, true); // adjustable: start at 1
// or, for fixed 4 partitions
new HashShuffleSpec(clusterBy, 4, false);
Defensive patterns

Strategy: validation

Validate before calling

if (adjustable && numPartitions != 1) {
  throw new IllegalArgumentException("Adjustable hash shuffles must start with numPartitions = 1");
}

Type guard

static boolean validHashSpecParams(int numPartitions, boolean adjustable) {
  return !adjustable || numPartitions == 1;
}

Try / catch

try {
  spec = new HashShuffleSpec(clusterBy, numPartitions, adjustable);
} catch (IllegalArgumentException e) {
  spec = new HashShuffleSpec(clusterBy, 1, adjustable); // or set adjustable=false
}

Prevention

When it happens

Trigger: Constructing HashShuffleSpec(clusterBy, numPartitions, adjustable=true) where numPartitions != 1 — e.g. ShuffleSpecFactory.create for HASH kind with adjustable workers config and a partition count > 1.

Common situations: Query context settings that both set an explicit multi-partition count and enable adjustable partitioning (e.g. dynamic worker scaling with fixed partitions); miswired factory parameters.

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/6d95e10e216e5a6e. Report an issue: GitHub.