apache/cassandra · error · InvalidRequestException
Analysis options are not supported on primary key columns…
Error message
Analysis options are not supported on primary key columns, but found
What it means
SAI does not allow analyzer (text-processing) options on primary key columns. validateOptions extracts analyzer options from the CREATE INDEX options and, if the index target is a partition/clustering column and any analysis options are present, throws this InvalidRequestException (ANALYSIS_ON_KEY_COLUMNS_MESSAGE plus the offending options).
Solutions
- Remove all analyzer options from the CREATE INDEX statement for primary key columns.
- Create the SAI index without an analyzer class; key columns are matched exactly.
- If case-insensitive matching on a key column is needed, model the data differently (e.g., a denormalized lowercase column) instead of using analyzer options.
Example fix
// before
CREATE CUSTOM INDEX ON ks.tbl (partition_col) USING 'StorageAttachedIndex'
WITH OPTIONS = {'case_sensitive': 'false'};
// after
CREATE CUSTOM INDEX ON ks.tbl (partition_col) USING 'StorageAttachedIndex'; Defensive patterns
Strategy: validation
Validate before calling
const isPrimaryKey = schema.partitionKeys.concat(schema.clusteringKeys).some(k => k.name === targetColumn); if (isPrimaryKey && Object.keys(indexOptions).length > 0) throw new Error('no analyzer options allowed on key columns'); Try / catch
catch (InvalidRequestException e) { if (e.getMessage().contains("Analysis options are not supported on primary key columns")) { // strip options and retry without them } } Prevention
- Never copy analyzer options onto indexes of key columns
- Gate option emission in DDL generators on the column's role
- Keep key-column indexes option-free
When it happens
Trigger: CREATE CUSTOM INDEX with options like 'case_sensitive': 'false' or 'normalize_upper': 'true' (any NonTokenizingOptions keys) on a PRIMARY KEY column (partition key or clustering column).
Common situations: Adding case_sensitive/normalize options to an index on a clustering column copied from a text-column index definition; templated DDL generators applying analyzer options to all indexed columns.
Related errors
- CQL type
- A storage-attached index cannot be created over multiple…
- An error occurred while scrubbing the partition with key
- Cannot create more than one storage-attached index on the…
- Cannot include more than one non-primary key column in…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/77c2155d3e8902b0.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java:280
throw new InvalidRequestException("Failed to retrieve target column for: " + targetColumn);
}
// In order to support different index targets on non-frozen map, ie. KEYS, VALUE, ENTRIES, we need to put index
// name as part of index file name instead of column name. We only need to check that the target is different
// between indexes. This will only allow indexes in the same column with a different IndexTarget.Type.
//
// Note that: "metadata.indexes" already includes current index
if (metadata.indexes.stream().filter(index -> index.getIndexClassName().equals(StorageAttachedIndex.class.getName()))
.map(index -> TargetParser.parse(metadata, index.options.get(IndexTarget.TARGET_OPTION_NAME)))
.filter(Objects::nonNull).filter(t -> t.equals(target)).count() > 1)
{
throw new InvalidRequestException("Cannot create more than one storage-attached index on the same column: " + target.left);
}
Map<String, String> analysisOptions = AbstractAnalyzer.getAnalyzerOptions(options);
if (target.left.isPrimaryKeyColumn() && !analysisOptions.isEmpty())
{
throw new InvalidRequestException(ANALYSIS_ON_KEY_COLUMNS_MESSAGE + new CqlBuilder().append(analysisOptions));
}
IndexTermType indexTermType = IndexTermType.create(target.left, metadata.partitionKeyColumns(), target.right);
AbstractAnalyzer.fromOptions(indexTermType, analysisOptions);
IndexWriterConfig config = IndexWriterConfig.fromOptions(null, indexTermType, options);
// If we are indexing map entries we need to validate the subtypes
if (indexTermType.isComposite())
{
for (IndexTermType subType : indexTermType.subTypes())
{
if (!SUPPORTED_TYPES.contains(subType.asCQL3Type()) && !subType.isFrozen())
throw new InvalidRequestException("Unsupported type: " + subType.asCQL3Type());
}
}
else if (!SUPPORTED_TYPES.contains(indexTermType.asCQL3Type()) && !indexTermType.isFrozen())
{
throw new InvalidRequestException("Unsupported type: " + indexTermType.asCQL3Type());View on GitHub (pinned to 88fd0f6a0e)