{"record":{"id":"7b1a4a52585fca2c","repo":"apache/druid","slug":"cannot-mix-sortable-and-unsortable-key-columns","errorCode":null,"errorMessage":"Cannot mix sortable and unsortable key columns","messagePattern":"Cannot mix sortable and unsortable key columns","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/frame/key/ClusterBy.java","lineNumber":73,"sourceCode":"  )\n  {\n    this.columns = Preconditions.checkNotNull(columns, \"columns\");\n    this.bucketByCount = bucketByCount;\n\n    if (bucketByCount < 0 || bucketByCount > columns.size()) {\n      throw new IAE(\"Invalid bucketByCount [%d]\", bucketByCount);\n    }\n\n    // Key must be 100% sortable or 100% nonsortable. If empty, call it sortable.\n    boolean sortable = true;\n\n    for (int i = 0; i < columns.size(); i++) {\n      final KeyColumn column = columns.get(i);\n\n      if (i == 0) {\n        sortable = column.order().sortable();\n      } else if (sortable != column.order().sortable()) {\n        throw new IAE(\"Cannot mix sortable and unsortable key columns\");\n      }\n    }\n\n    this.sortable = sortable;\n  }\n\n  /**\n   * Create an empty key.\n   */\n  public static ClusterBy none()\n  {\n    return new ClusterBy(Collections.emptyList(), 0);\n  }\n\n  /**\n   * The columns that comprise this key, in order.\n   */\n  @JsonProperty","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/frame/key/ClusterBy.java#L55-L91","documentation":"ClusterBy requires all key columns to be uniformly sortable or uniformly non-sortable, because mixing them prevents a consistent key ordering for partitioning/shuffling. If the first column's order is sortable and any later column's is not (or vice versa), construction fails.","triggerScenarios":"Building a ClusterBy from a column list where KeyColumn.order().sortable() differs between columns — e.g. clustering on a mix of standard comparable columns and non-sortable column types (like complex/sketch columns).","commonSituations":"MSQ CLUSTERED BY including a non-sortable expression or complex column alongside regular columns; user typos in SQL clustering expressions; new column types whose order is non-sortable being added to an existing clustering spec.","solutions":["Change the clustering expression so every column uses a sortable ordering (avoid complex/sketch-type columns in CLUSTERED BY).","Split the clustering key so non-sortable columns are not included, or wrap them with a sortable expression (e.g. cast or stringify).","Inspect each KeyColumn's order().sortable() before constructing ClusterBy programmatically.","If this comes from a generated plan, check the SQL layer's column ordering resolution for the query."],"exampleFix":"// before\n// CLUSTERED BY region, APPROX_COUNT_DISTINCT_DS_HLL(user)  -> mixed sortability\n// after\n// CLUSTERED BY region, user  (use only sortable columns in the clustering key)","handlingStrategy":"validation","validationCode":"boolean first = columns.get(0).order().sortable();\nfor (KeyColumn c : columns) {\n  if (c.order().sortable() != first) {\n    throw new IllegalArgumentException(\"Mixed sortable/unsortable clustering columns\");\n  }\n}","typeGuard":"static boolean uniformlySortable(List<KeyColumn> columns) {\n  if (columns.isEmpty()) return true;\n  boolean s = columns.get(0).order().sortable();\n  return columns.stream().allMatch(c -> c.order().sortable() == s);\n}","tryCatchPattern":"try {\n  new ClusterBy(columns, bucketByCount);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"mix sortable\")) {\n    columns = dropUnsortableColumns(columns);\n    new ClusterBy(columns, Math.min(bucketByCount, columns.size()));\n  } else {\n    throw e;\n  }\n}","preventionTips":["Only include sortable columns (no complex/sketch types) in CLUSTERED BY.","Check KeyColumn.order().sortable() programmatically before building ClusterBy.","Sanitize user SQL clustering expressions to reject non-sortable column types.","Document which column types are non-sortable for spec authors."],"tags":["configuration","validation","druid","msq"],"backgroundTag":"invalid-argument-value","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"}