apache/cassandra · error · InvalidRequestException

Secondary indexes are not supported on PRIMARY KEY columns…

Error message

Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables

What it means

In COMPACT STORAGE (thrift-legacy) tables, primary key columns have a restricted on-disk encoding and cannot be indexed by a legacy secondary index. Creating a 2i on any PRIMARY KEY column of a compact table throws InvalidRequestException (PRIMARY_KEY_IN_COMPACT_STORAGE).

Solutions

  1. Run `ALTER TABLE ... DROP COMPACT STORAGE` (after cluster upgrade prerequisites) to convert the table, then create the index.
  2. Query the primary-key column directly by its key instead of indexing it.
  3. Migrate data to a new non-compact table with the desired index and switch reads over.

Example fix

-- before
CREATE INDEX ON legacy_compact (clustering_col); -- fails

-- after
ALTER TABLE legacy_compact DROP COMPACT STORAGE;
CREATE INDEX ON legacy_compact (clustering_col);
Defensive patterns

Strategy: validation

Validate before calling

TableMetadata t = session.getCluster().getMetadata().getKeyspace("ks").getTable("t");
boolean compact = t.getOptions().getCompactStorage();
boolean isPkCol = t.getPartitionKey().stream().anyMatch(c -> c.getName().equals(col))
              || t.getClusteringColumns().keySet().stream().anyMatch(c -> c.getName().equals(col));
if (compact && isPkCol) throw new IllegalStateException("cannot 2i a PK column of a COMPACT STORAGE table");

Try / catch

try { session.execute("CREATE INDEX ON ks.t (pkcol)"); }
catch (InvalidQueryException e) {
  if (e.getMessage().contains("PRIMARY KEY columns in COMPACT STORAGE"))
      throw new IllegalStateException("DROP COMPACT STORAGE first or query by key", e);
  throw e;
}

Prevention

When it happens

Trigger: `CREATE INDEX ... ON compact_table (primary_key_column)` where the table was created `WITH COMPACT STORAGE` and the target column `isPrimaryKeyColumn()` is true (partition key or clustering column).

Common situations: Working with thrift-era CQL3 tables kept COMPACT STORAGE for compatibility; migration scripts that blindly index all columns.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/e036517f048f7975. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:283

        if (column.type.referencesDuration())
        {
            if (column.type.isCollection())
                throw ire(COLLECTIONS_WITH_DURATIONS_NOT_SUPPORTED);

            if (column.type.isTuple())
                throw ire(TUPLES_WITH_DURATIONS_NOT_SUPPORTED);

            if (column.type.isUDT())
                throw  ire(UDTS_WITH_DURATIONS_NOT_SUPPORTED);

            throw ire(DURATIONS_NOT_SUPPORTED);
        }

        if (table.isCompactTable())
        {
            TableMetadata.CompactTableMetadata compactTable = (TableMetadata.CompactTableMetadata) table;
            if (column.isPrimaryKeyColumn())
                throw new InvalidRequestException(PRIMARY_KEY_IN_COMPACT_STORAGE);
            if (compactTable.compactValueColumn.equals(column))
                throw new InvalidRequestException(COMPACT_COLUMN_IN_COMPACT_STORAGE);
        }

        if (column.isPartitionKey() && table.partitionKeyColumns().size() == 1)
            throw ire(ONLY_PARTITION_KEY, column);

        if (target.type == Type.FULL && isNonSAIIndex && (!baseType.isCollection() || column.type.isMultiCell()))
            throw ire(FULL_ON_FROZEN_COLLECTIONS);

        if (!baseType.isCollection() && target.type != Type.SIMPLE)
            throw ire(NON_COLLECTION_SIMPLE_INDEX, target.type, column);

        // Frozen collections are only supported with SAI indexes.
        if (isNonSAIIndex && baseType.isCollection() && !column.type.isMultiCell())
        {
            if (target.type == Type.VALUES || target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES)
            {

View on GitHub (pinned to 88fd0f6a0e)