{"record":{"id":"2a74eb8cb7dc5778","repo":"apache/druid","slug":"partition-count-must-be-at-least-1","errorCode":null,"errorMessage":"Partition count must be at least 1","messagePattern":"Partition count must be at least 1","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/kernel/GlobalSortMaxCountShuffleSpec.java","lineNumber":65,"sourceCode":"  private final boolean adjustable;\n\n  @JsonCreator\n  public GlobalSortMaxCountShuffleSpec(\n      @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,","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/kernel/GlobalSortMaxCountShuffleSpec.java#L47-L83","documentation":"GlobalSortMaxCountShuffleSpec partitions output by a global sort with a maximum partition count. maxPartitions must be >= 1; values below 1 make no sense as a partition count, so the constructor throws IAE.","triggerScenarios":"Constructing GlobalSortMaxCountShuffleSpec (directly or via JSON deserialization of an MSQ task) with maxPartitions = 0 or negative - typically from a computed limit like maxNumPartitions derived from an empty/zero worker count or unset config.","commonSituations":"Query-generation code computing partition count as workers.size() when no workers are known; clients hand-writing shuffle spec JSON with 0; numeric truncation bugs turning small fractions into 0.","solutions":["Set maxPartitions to a positive value (at least 1) in the shuffle spec / query JSON.","Fix the code computing maxNumPartitions to clamp to a minimum of 1 (e.g. Math.max(1, computed)).","Check MSQ context parameters (e.g. maxPartitions / limit settings) that feed this value."],"exampleFix":"// before\nint maxPartitions = workers.size(); // can be 0\n// after\nint maxPartitions = Math.max(1, workers.size());","handlingStrategy":"validation","validationCode":"if (maxPartitions < 1) {\n  throw new IllegalArgumentException(\"maxPartitions must be >= 1, got \" + maxPartitions);\n}\nnew GlobalSortMaxCountShuffleSpec(clusterBy, maxPartitions, aggregate, limitHint, adjustable);","typeGuard":null,"tryCatchPattern":"try {\n  spec = objectMapper.readValue(json, GlobalSortMaxCountShuffleSpec.class);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().equals(\"Partition count must be at least 1\")) {\n    // clamp and rebuild with maxPartitions = 1\n  } else {\n    throw e;\n  }\n}","preventionTips":["Clamp computed partition counts with Math.max(1, value).","Guard worker-count-derived values against empty worker lists.","Validate shuffle spec JSON before task submission."],"tags":["msq","shuffle-spec","validation","value-out-of-range"],"backgroundTag":"value-out-of-range","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"}