apache/cassandra · error · InvalidRequestException
Secondary indexes are not supported on duration columns
Error message
Secondary indexes are not supported on duration columns
What it means
Cassandra does not allow secondary indexes on columns of type `duration` at all. Duration lacks the comparison semantics index backends rely on for equality/range matching. This is the fallback branch of the duration check in validateIndexTarget after collection/tuple/UDT cases.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:276
boolean isNonSAIIndex = !isSAIIndex(attrs);
// TODO: this check needs to be removed with CASSANDRA-20235
if ((kind == IndexMetadata.Kind.CUSTOM))
validateCustomIndexColumnName(target.column.toString());
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)View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Change the column type to bigint (store milliseconds) or timestamp and index that.
- Filter by duration in application code or via ALLOW FILTERING on a scan (with care).
- Denormalize into buckets (e.g. duration_class text) that can be indexed.
Example fix
// before CREATE INDEX ON jobs (elapsed); // elapsed duration // after ALTER TABLE jobs ADD elapsed_ms bigint; CREATE INDEX ON jobs (elapsed_ms);
Defensive patterns
Strategy: validation
Validate before calling
if (column.type.toString() === 'duration') throw new Error('duration columns cannot be secondary-indexed'); Type guard
const isIndexableScalar = (t) => !t.referencesDuration();
Try / catch
try { session.execute(ddl); } catch (e) { if (/not supported on duration columns/.test(e.message)) { /* switch to bigint/timestamp */ } else throw e; } Prevention
- Store durations as bigint milliseconds when range queries are planned
- Exclude duration from auto-index tooling column lists
When it happens
Trigger: `CREATE INDEX ON t (dur_col)` where dur_col is a plain duration column (regular, static, or even key columns), via any index kind including custom/SAI.
Common situations: Tracking SLA/elapsed-time with duration then trying to find rows by duration range; writing generic schema tooling that blindly indexes all columns.
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
- Secondary indexes are not supported on collections containin
- Secondary indexes are not supported on tuples containing dur
- Secondary indexes are not supported on UDTs containing durat
- Cannot create secondary index on the only partition key colu
- full() non-SAI indexes can only be created on frozen collect
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/c9db9f29a19ac019.
Report an issue: GitHub.