{"record":{"id":"ec618ab736e3bf6e","repo":"apache/druid","slug":"partition-count-must-be-1-when-adjustable-is-true","errorCode":null,"errorMessage":"Partition count must be 1 when adjustable is true, but was [%d]","messagePattern":"Partition count must be 1 when adjustable is true, but was \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/kernel/GlobalSortMaxCountShuffleSpec.java","lineNumber":69,"sourceCode":"      @JsonProperty(\"clusterBy\") final ClusterBy clusterBy,\n      @JsonProperty(\"partitions\") final int maxPartitions,\n      @JsonProperty(\"aggregate\") final boolean aggregate,\n      @JsonProperty(\"limitHint\") final Long limitHint,\n      @JsonProperty(\"adjustable\") final boolean adjustable\n  )\n  {\n    this.clusterBy = Preconditions.checkNotNull(clusterBy, \"clusterBy\");\n    this.maxPartitions = maxPartitions;\n    this.aggregate = aggregate;\n    this.limitHint = limitHint == null ? UNLIMITED : limitHint;\n    this.adjustable = adjustable;\n\n    if (maxPartitions < 1) {\n      throw new IAE(\"Partition count must be at least 1\");\n    }\n\n    if (adjustable && maxPartitions != 1) {\n      throw new IAE(\"Partition count must be 1 when adjustable is true, but was [%d]\", maxPartitions);\n    }\n\n    if (!clusterBy.sortable()) {\n      throw new IAE(\"ClusterBy key must be sortable\");\n    }\n\n    if (clusterBy.getBucketByCount() > 0) {\n      // Only GlobalSortTargetSizeShuffleSpec supports bucket-by.\n      throw new IAE(\"Cannot bucket with %s partitioning\", TYPE);\n    }\n  }\n\n  public GlobalSortMaxCountShuffleSpec(\n      final ClusterBy clusterBy,\n      final int maxPartitions,\n      final boolean aggregate,\n      final Long limitHint\n  )","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/kernel/GlobalSortMaxCountShuffleSpec.java#L51-L87","documentation":"An adjustable GlobalSortMaxCountShuffleSpec lets the engine change the partition count during execution, and by definition it must be capped at a single partition. If adjustable is true but maxPartitions != 1, the constructor rejects the combination with IAE.","triggerScenarios":"Creating the spec with adjustable=true and maxPartitions set to any value other than 1, either via direct construction or JSON like {\"type\":\"maxCountSorting\",\"maxPartitions\":4,\"adjustable\":true}.","commonSituations":"Query builders that set adjustable automatically while preserving a user-supplied maxPartitions; hand-written task JSON combining both fields inconsistently; conversion bugs between shuffle spec types during SQL-to-native translation.","solutions":["Set maxPartitions to 1 when adjustable is true.","Or set adjustable to false if you intend to keep a fixed maxPartitions > 1.","Fix query-generation code to normalize adjustable specs to maxPartitions=1."],"exampleFix":"// before\nnew GlobalSortMaxCountShuffleSpec(clusterBy, 4, false, true, true); // adjustable with 4\n// after\nnew GlobalSortMaxCountShuffleSpec(clusterBy, 1, false, true, true);","handlingStrategy":"validation","validationCode":"if (adjustable && maxPartitions != 1) {\n  maxPartitions = 1; // adjustable specs must be capped at 1\n}\nnew GlobalSortMaxCountShuffleSpec(clusterBy, maxPartitions, aggregate, limitHint, adjustable);","typeGuard":null,"tryCatchPattern":"try {\n  spec = buildShuffleSpec(...);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Partition count must be 1 when adjustable\")) {\n    spec = buildShuffleSpec(... maxPartitions = 1 ...);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Normalize adjustable specs to maxPartitions=1 in query-generation code.","Don't mix user-supplied maxPartitions with engine-set adjustable flags.","Add round-trip tests for shuffle spec serialization."],"tags":["msq","shuffle-spec","validation","conflicting-options"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}