{"record":{"id":"a82412b1f518d6f5","repo":"apache/druid","slug":"cannot-create-comparator-for-array-type-s","errorCode":null,"errorMessage":"Cannot create comparator for array type %s.","messagePattern":"Cannot create comparator for array type (.+?)\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/orderby/DefaultLimitSpec.java","lineNumber":475,"sourceCode":"        };\n      } else if (columnType.getElementType().equals(ColumnType.STRING)) {\n        arrayComparator = (o1, o2) -> {\n          if (stringComparator == null\n              || StringComparators.NATURAL.equals(stringComparator)\n              || StringComparators.LEXICOGRAPHIC.equals(stringComparator)) {\n            return columnType.getNullableStrategy().compare(\n                DimensionHandlerUtils.coerceToStringArray(o1),\n                DimensionHandlerUtils.coerceToStringArray(o2)\n            );\n          }\n          return new DimensionComparisonUtils.ArrayComparator<>(stringComparator)\n              .compare(\n                  DimensionHandlerUtils.coerceToStringArray(o1),\n                  DimensionHandlerUtils.coerceToStringArray(o2)\n              );\n        };\n      } else {\n        throw new ISE(\"Cannot create comparator for array type %s.\", columnType.toString());\n      }\n    }\n    final Comparator comparatorToUse;\n    if (arrayComparator != null) {\n      comparatorToUse = arrayComparator;\n    } else {\n      comparatorToUse = DimensionComparisonUtils.isNaturalComparator(columnType.getType(), stringComparator)\n                        ? columnType.getNullableStrategy()\n                        : stringComparator;\n    }\n\n    return Ordering.from(\n        Comparator.comparing(\n            (ResultRow row) -> {\n              if (columnType.isArray()) {\n                // Arrays have a specialized comparator, that applies the ordering per element. That will handle the casting\n                // and the comparison\n                return row.get(column);","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/orderby/DefaultLimitSpec.java#L457-L493","documentation":"DefaultLimitSpec builds Comparators to apply a topN-style limit/order-by on group-by results. Comparator construction only supports scalar column types plus string-array and primitive-array types (compared via DimensionHandlerUtils.coerceToStringArray); for any other array type (e.g. COMPLEX arrays or otherwise unsupported array dimensions) it throws this ISE rather than producing a wrong ordering.","triggerScenarios":"Calling makeComparator/dimensionOrdering with an OrderByColumnSpec whose column has an array ColumnType not in the supported set (e.g. a complex or long/double array dimension ordering) while applying a DefaultLimitSpec to group-by results.","commonSituations":"Ordering group-by output by an array-typed dimension such as a filtered/transformed array column, or after upgrading Druid and introducing array-typed columns into queries that previously used scalar dimensions with limit specs.","solutions":["Change the query to order by a scalar column, or project/flatten the array into a scalar before applying the limit spec","Remove or restrict the OrderByColumnSpec on the array column and sort client-side after the query returns","If support is genuinely needed, extend dimensionOrdering to add a comparator branch for the missing array type and file an issue upstream"],"exampleFix":"// before\nOrderByColumnSpec spec = OrderByColumnSpec.ascending(\"arrDim\"); // arrDim is a complex array\nnew DefaultLimitSpec(ImmutableList.of(spec), 100)\n// after\nOrderByColumnSpec spec = OrderByColumnSpec.ascending(\"scalarDim\"); // order by scalar instead","handlingStrategy":"validation","validationCode":"ColumnCapabilities caps = rowSignature.getColumnCapabilities(colName);\nif (caps != null && caps.getType().isArray() &&\n    !(caps.getType() == ColumnType.STRING_ARRAY || caps.getType() == ColumnType.LONG_ARRAY || caps.getType() == ColumnType.DOUBLE_ARRAY)) {\n  throw new IllegalArgumentException(\"Cannot order by array column of type \" + caps.getType());\n}","typeGuard":"boolean isOrderableArray(ColumnType t) {\n  return t.isArray()\n    && (ColumnType.STRING_ARRAY.equals(t) || ColumnType.LONG_ARRAY.equals(t) || ColumnType.DOUBLE_ARRAY.equals(t));\n}","tryCatchPattern":"try {\n  return limitSpec.build(...) ;\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Cannot create comparator\")) {\n    // fall back to client-side sort or scalar projection\n  } else throw e;\n}","preventionTips":["Only add OrderByColumnSpec entries on scalar columns or supported array types (string/long/double arrays)","Check the row signature's column capabilities before attaching a DefaultLimitSpec","Sort array columns client-side after retrieval instead of server-side"],"tags":["group-by","comparator","arrays","unsupported-type"],"backgroundTag":"unsupported-operation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}