apache/druid · error · IllegalStateException

keyColumns[%s] must all be contained in rowSignature[%s]

Error message

keyColumns[%s] must all be contained in rowSignature[%s]

What it means

Key columns must be present in the table's row signature since indexes are built from column functions derived from the signature. The RowBasedIndexedTable constructor validates that keyColumns ⊆ rowSignature column names and throws ISE otherwise.

Source

Thrown at processing/src/main/java/org/apache/druid/segment/join/table/RowBasedIndexedTable.java:91

      final List<RowType> table,
      final RowAdapter<RowType> rowAdapter,
      final RowSignature rowSignature,
      final Set<String> keyColumns,
      final String version,
      @Nullable
      final byte[] cacheKey
  )
  {
    this.table = table;
    this.rowSignature = rowSignature;
    this.columnFunctions =
        rowSignature.getColumnNames().stream().map(rowAdapter::columnFunction).collect(Collectors.toList());
    this.keyColumns = keyColumns;
    this.version = version;
    this.cacheKey = cacheKey;

    if (!ImmutableSet.copyOf(rowSignature.getColumnNames()).containsAll(keyColumns)) {
      throw new ISE(
          "keyColumns[%s] must all be contained in rowSignature[%s]",
          String.join(", ", keyColumns),
          rowSignature
      );
    }

    indexes = new ArrayList<>(rowSignature.size());

    for (int i = 0; i < rowSignature.size(); i++) {
      final String column = rowSignature.getColumnName(i);
      final Index m;

      if (keyColumns.contains(column)) {
        final ColumnType keyType =
            rowSignature.getColumnType(column).orElse(IndexedTableJoinMatcher.DEFAULT_KEY_TYPE);

        final RowBasedIndexBuilder builder = new RowBasedIndexBuilder(keyType);
        final Function<RowType, Object> columnFunction = columnFunctions.get(i);

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Fix the keyColumns list to use exact column names from rowSignature
  2. Verify case-sensitivity of column names (Druid columns are case-sensitive)
  3. Derive key columns programmatically by checking rowSignature.getColumnNames() first
  4. Align the signature with the key columns actually needed for the join

Example fix

// before
new RowBasedIndexedTable<>(adapter, signature, version, Set.of("User_Id"), cacheKey);
// after
// signature has column "userId"
new RowBasedIndexedTable<>(adapter, signature, version, Set.of("userId"), cacheKey);
Defensive patterns

Strategy: validation

Validate before calling

Set<String> sigCols = ImmutableSet.copyOf(rowSignature.getColumnNames());
if (!sigCols.containsAll(keyColumns)) { throw new IllegalArgumentException("key columns not in signature"); }

Try / catch

try { table = new RowBasedIndexedTable<>(...); } catch (ISE e) { /* log and fix keyColumns/signature */ }

Prevention

When it happens

Trigger: Constructing RowBasedIndexedTable (directly or via Builder) passing a keyColumns set containing a column name not in the RowSignature, e.g. a typo or casing mismatch ('UserID' vs 'userId').

Common situations: Typo in key column names; key columns defined for a different schema version; programmatic table construction where signature and keyColumns drift; case-sensitivity mistakes.

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/63cc255a6ab22cc6. Report an issue: GitHub.