apache/cassandra · error · InvalidRequestException
Secondary indexes are not supported on UDTs containing durat
Error message
Secondary indexes are not supported on UDTs containing durations
What it means
Cassandra rejects secondary indexes on user-defined types (UDTs) that contain a `duration` field. Since UDT fields are not individually indexable anyway and duration is unindexable, any UDT referencing duration is rejected. Raised in validateIndexTarget when the column type is a UDT referencing duration.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:274
AbstractType<?> baseType = column.type.unwrap();
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);View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Remove the duration field from the UDT or change it to bigint/timestamp.
- Create a narrower UDT without duration for the indexed column.
- Denormalize the fields you need to query into a dedicated indexed column.
Example fix
// before CREATE TYPE interval (start_ts timestamp, len duration); CREATE INDEX ON schedules (span); // span frozen<interval> // after CREATE TYPE interval_idx (start_ts timestamp, len_ms bigint); CREATE INDEX ON schedules (span);
Defensive patterns
Strategy: validation
Validate before calling
if (column.type.isUDT() && column.type.referencesDuration()) throw new Error('unindexable UDT: contains duration field'); Type guard
const isIndexableUdt = (t) => t.isUDT() && !t.referencesDuration();
Try / catch
try { session.execute(ddl); } catch (e) { if (/not supported on UDTs containing durations/.test(e.message)) { /* revise UDT definition */ } else throw e; } Prevention
- Keep duration out of UDTs that participate in indexes
- Audit shared UDT definitions before adding indexes in any table
When it happens
Trigger: `CREATE INDEX ON t (udt_col)` where udt_col's type definition includes a duration field (e.g. CREATE TYPE interval (start timestamp, len duration)), including frozen and non-frozen UDTs.
Common situations: Indexing a frozen UDT with full() after adding a duration field; shared UDT reused across tables where one table's index DDL no longer validates.
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 duration columns
- Not enough bytes to read size of %dth field %s
- Not enough bytes to read %dth field %s
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/90d0489c666831f5.
Report an issue: GitHub.