apache/cassandra · error · InvalidRequestException

duration type is not supported for PRIMARY KEY column

Error message

duration type is not supported for PRIMARY KEY column '%s'

What it means

A materialized view's primary key must contain every partition key column of the base table. Because view rows are maintained per base partition, omitting any base partition key column would break correct update routing, so validation enforces the containment invariant.

Solutions

  1. Include all base-table partition key columns in the view's PRIMARY KEY
  2. If a narrower key is needed, that restriction is unsupported by MVs; use a denormalized table maintained by application logic or secondary indexes

Example fix

// before
CREATE MATERIALIZED VIEW mv AS SELECT pk1, pk2, ck FROM base WHERE pk1 IS NOT NULL AND pk2 IS NOT NULL AND ck IS NOT NULL PRIMARY KEY ((pk1), ck);
// after
CREATE MATERIALIZED VIEW mv AS SELECT pk1, pk2, ck FROM base WHERE pk1 IS NOT NULL AND pk2 IS NOT NULL AND ck IS NOT NULL PRIMARY KEY ((pk1, pk2), ck);
Defensive patterns

Strategy: validation

Validate before calling

for (String pk : basePartitionKeys) if (!primaryKeyCols.contains(pk)) throw new IllegalArgumentException("MV primary key must include base partition key: " + pk);

Try / catch

try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("must contain all base table primary key columns")) { /* add missing partition key columns */ } }

Prevention

When it happens

Trigger: CREATE MATERIALIZED VIEW whose PRIMARY KEY omits one of the base table's partition key columns, e.g. base has ((pk1, pk2), ck) but the view declares PRIMARY KEY (pk1, ck).

Common situations: Attempting to 'reduce' the partition key to get broader queries; forgetting one column of a composite partition key when hand-writing the clause; generated DDL missing a column.

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


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java:265

            if (!primaryKeyColumns.add(name))
                throw ire("Duplicate column '%s' in PRIMARY KEY clause for materialized view '%s'", name, viewName);

            AbstractType<?> type = column.type;

            if (type.isMultiCell())
            {
                if (type.isCollection())
                    throw ire("Invalid non-frozen collection type '%s' for PRIMARY KEY column '%s'", type, name);
                else
                    throw ire("Invalid non-frozen user-defined type '%s' for PRIMARY KEY column '%s'", type, name);
            }

            if (type.isCounter())
                throw ire("counter type is not supported for PRIMARY KEY column '%s'", name);

            if (type.referencesDuration())
                throw ire("duration type is not supported for PRIMARY KEY column '%s'", name);
        });

        // If we give a clustering order, we must explicitly do so for all aliases and in the order of the PK
        if (!clusteringOrder.isEmpty() && !clusteringColumns.equals(new ArrayList<>(clusteringOrder.keySet())))
            throw ire("Clustering key columns must exactly match columns in CLUSTERING ORDER BY directive");

        /*
         * We need to include all of the primary key columns from the base table in order to make sure that we do not
         * overwrite values in the view. We cannot support "collapsing" the base table into a smaller number of rows in
         * the view because if we need to generate a tombstone, we have no way of knowing which value is currently being
         * used in the view and whether or not to generate a tombstone. In order to not surprise our users, we require
         * that they include all of the columns. We provide them with a list of all of the columns left to include.
         */
        List<ColumnIdentifier> missingPrimaryKeyColumns =
            Lists.newArrayList(filter(transform(table.primaryKeyColumns(), c -> c.name), c -> !primaryKeyColumns.contains(c)));

        if (!missingPrimaryKeyColumns.isEmpty())
        {

View on GitHub (pinned to 88fd0f6a0e)