apache/druid · error · DruidException

clusteringColumns must be the leading prefix of columns, in

Error message

clusteringColumns must be the leading prefix of columns, in order; got %s vs columns prefix %s

What it means

ClusteredValueGroupsBaseTableProjectionSpec.validate rejects projection specs whose clusteringColumns do not form an exact leading prefix of columns in the same order. Druid's clusteredValueGroups base-table projection encodes clustering as the first N columns of the projection's column list, so a mismatch (extra clustering columns, or columns out of order) makes the spec invalid. The message shows the full columns list versus the clustering prefix actually found.

Source

Thrown at processing/src/main/java/org/apache/druid/data/input/impl/ClusteredValueGroupsBaseTableProjectionSpec.java:301

      }
    }
    return builder()
        .virtualColumns(VirtualColumns.create(remaining))
        .clusteringColumns(clusteringColumns)
        .columns(columns)
        .build();
  }

  private static void validate(List<DimensionSchema> columns, List<String> clusteringColumns)
  {
    if (CollectionUtils.isNullOrEmpty(clusteringColumns)) {
      throw InvalidInput.exception("clusteringColumns must be non-empty for clusteredValueGroups base table");
    }
    if (CollectionUtils.isNullOrEmpty(columns)) {
      throw InvalidInput.exception("columns must be non-empty for clusteredValueGroups base table");
    }
    if (clusteringColumns.size() > columns.size()) {
      throw clusteringPrefixException(columns, clusteringColumns);
    }
    for (int i = 0; i < clusteringColumns.size(); i++) {
      final DimensionSchema clusteringColumn = columns.get(i);
      if (!clusteringColumn.getName().equals(clusteringColumns.get(i))) {
        throw clusteringPrefixException(columns, clusteringColumns);
      }
      // Clustering values are dictionary-encoded into per-type dictionaries on the write side, which supports only
      // these scalar types; reject anything else up front rather than failing later at ingest.
      if (!Projections.isAllowedClusteringType(clusteringColumn.getColumnType())) {
        throw InvalidInput.exception(
            "clustering column [%s] has unsupported type [%s]; clustering columns must be STRING, LONG, DOUBLE, or FLOAT",
            clusteringColumn.getName(),
            clusteringColumn.getColumnType()
        );
      }
    }

    final Set<String> seen = Sets.newHashSetWithExpectedSize(columns.size());

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Reorder columns so the clustering columns come first, in exactly the same order as clusteringColumns.
  2. Ensure every clustering column appears in columns with an identical name.
  3. Remove clustering columns that are not part of the leading prefix, or add them to columns if intended.
  4. Validate the projection spec JSON (names and order) before submitting the ingestion/projection spec.

Example fix

// before: mismatched order
clusteringColumns: ["country", "city"]
columns: ["city", "country", "ts"]
// after: clustering columns are the ordered prefix
clusteringColumns: ["country", "city"]
columns: ["country", "city", "ts"]
Defensive patterns

Strategy: validation

Validate before calling

// ensure clusteringColumns is an ordered prefix of column names before building the spec
List<String> names = columns.stream().map(DimensionSchema::getName).collect(Collectors.toList());
if (names.size() < clusteringColumns.size() ||
    !names.subList(0, clusteringColumns.size()).equals(clusteringColumns)) {
  throw new IllegalArgumentException("clusteringColumns must be a leading prefix of columns, in order");
}

Try / catch

try { new ClusteredValueGroupsBaseTableProjectionSpec(...); } catch (DruidException e) { if (e.getMessage().contains("leading prefix")) { fixColumnOrder(); } throw e; }

Prevention

When it happens

Trigger: Building a ClusteredValueGroupsBaseTableProjectionSpec (directly or via projection spec JSON) where clusteringColumns.size() > columns.size(), or where columns.get(i).getName() != clusteringColumns.get(i) for some i < clusteringColumns.size().

Common situations: Hand-written projection specs listing clustering columns not present in columns; reordering columns without reordering clusteringColumns; appending clustering columns beyond the declared column list; tooling generating the two lists independently.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/6c5d4331f991a9cd. Report an issue: GitHub.