{"record":{"id":"e036517f048f7975","repo":"apache/cassandra","slug":"secondary-indexes-are-not-supported-on-primary-key","errorCode":null,"errorMessage":"Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables","messagePattern":"Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java","lineNumber":283,"sourceCode":"        if (column.type.referencesDuration())\n        {\n            if (column.type.isCollection())\n                throw ire(COLLECTIONS_WITH_DURATIONS_NOT_SUPPORTED);\n\n            if (column.type.isTuple())\n                throw ire(TUPLES_WITH_DURATIONS_NOT_SUPPORTED);\n\n            if (column.type.isUDT())\n                throw  ire(UDTS_WITH_DURATIONS_NOT_SUPPORTED);\n\n            throw ire(DURATIONS_NOT_SUPPORTED);\n        }\n\n        if (table.isCompactTable())\n        {\n            TableMetadata.CompactTableMetadata compactTable = (TableMetadata.CompactTableMetadata) table;\n            if (column.isPrimaryKeyColumn())\n                throw new InvalidRequestException(PRIMARY_KEY_IN_COMPACT_STORAGE);\n            if (compactTable.compactValueColumn.equals(column))\n                throw new InvalidRequestException(COMPACT_COLUMN_IN_COMPACT_STORAGE);\n        }\n\n        if (column.isPartitionKey() && table.partitionKeyColumns().size() == 1)\n            throw ire(ONLY_PARTITION_KEY, column);\n\n        if (target.type == Type.FULL && isNonSAIIndex && (!baseType.isCollection() || column.type.isMultiCell()))\n            throw ire(FULL_ON_FROZEN_COLLECTIONS);\n\n        if (!baseType.isCollection() && target.type != Type.SIMPLE)\n            throw ire(NON_COLLECTION_SIMPLE_INDEX, target.type, column);\n\n        // Frozen collections are only supported with SAI indexes.\n        if (isNonSAIIndex && baseType.isCollection() && !column.type.isMultiCell())\n        {\n            if (target.type == Type.VALUES || target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES)\n            {","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java#L265-L301","documentation":"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).","triggerScenarios":"`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).","commonSituations":"Working with thrift-era CQL3 tables kept COMPACT STORAGE for compatibility; migration scripts that blindly index all columns.","solutions":["Run `ALTER TABLE ... DROP COMPACT STORAGE` (after cluster upgrade prerequisites) to convert the table, then create the index.","Query the primary-key column directly by its key instead of indexing it.","Migrate data to a new non-compact table with the desired index and switch reads over."],"exampleFix":"-- before\nCREATE INDEX ON legacy_compact (clustering_col); -- fails\n\n-- after\nALTER TABLE legacy_compact DROP COMPACT STORAGE;\nCREATE INDEX ON legacy_compact (clustering_col);","handlingStrategy":"validation","validationCode":"TableMetadata t = session.getCluster().getMetadata().getKeyspace(\"ks\").getTable(\"t\");\nboolean compact = t.getOptions().getCompactStorage();\nboolean isPkCol = t.getPartitionKey().stream().anyMatch(c -> c.getName().equals(col))\n              || t.getClusteringColumns().keySet().stream().anyMatch(c -> c.getName().equals(col));\nif (compact && isPkCol) throw new IllegalStateException(\"cannot 2i a PK column of a COMPACT STORAGE table\");","typeGuard":null,"tryCatchPattern":"try { session.execute(\"CREATE INDEX ON ks.t (pkcol)\"); }\ncatch (InvalidQueryException e) {\n  if (e.getMessage().contains(\"PRIMARY KEY columns in COMPACT STORAGE\"))\n      throw new IllegalStateException(\"DROP COMPACT STORAGE first or query by key\", e);\n  throw e;\n}","preventionTips":["Plan to DROP COMPACT STORAGE on legacy tables before adding indexes","Remember primary key columns are already queryable by key — indexing them is usually unnecessary","Audit thrift-era tables for COMPACT STORAGE before writing migration DDL"],"tags":["cassandra","compact-storage","secondary-index","thrift"],"backgroundTag":"unsupported-operation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}