apache/cassandra · error · InvalidRequestException

Cannot drop column on base table with materialized views

Error message

Cannot drop column %s on base table %s with materialized views

What it means

This InvalidRequestException is thrown when attempting to DROP a column on a base table that has one or more materialized views (or similar views) defined on it. Views derive their data from the base table's columns, so Cassandra refuses column drops that would break the view definitions.

Solutions

  1. Drop all materialized views on the table first (`DROP MATERIALIZED VIEW ks.view_name`), perform the column drop, then recreate the views with the new schema (views can be rebuilt from existing base data).
  2. If the view is no longer needed, just drop it and proceed with the ALTER TABLE.
  3. List existing views with `SELECT view_name FROM system_schema.views WHERE keyspace_name='ks' AND table_name='tbl'` to identify blockers.
  4. Restructure so views are created on a new table version if frequent column changes are expected.

Example fix

// before
ALTER TABLE users DROP last_login; -- users has MV users_by_login: fails
// after
DROP MATERIALIZED VIEW ks.users_by_login;
ALTER TABLE users DROP last_login;
CREATE MATERIALIZED VIEW ks.users_by_login AS SELECT ... FROM users WHERE ...;
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check for materialized views on the base table
ResultSet rs = session.execute(
  "SELECT view_name FROM system_schema.views WHERE keyspace_name=? AND table_name=?",
  ks, table);
boolean hasViews = rs.iterator().hasNext();
// if hasViews, drop/recreate views around the ALTER TABLE

Try / catch

try {
    session.execute("ALTER TABLE ks.tbl DROP " + column);
} catch (com.datastax.oss.driver.api.core.servererrors.InvalidQueryException e) {
    if (e.getMessage().contains("with materialized views")) {
        // drop MVs, retry ALTER, recreate MVs
    } else throw e;
}

Prevention

When it happens

Trigger: Executing `ALTER TABLE ks.base DROP col` when `keyspace.views.forTable(table.id)` is non-empty, i.e. any materialized view (or SASI-style view) exists over that base table. This applies even if the dropped column is not referenced in the view's SELECT or PRIMARY KEY.

Common situations: Developers who added a materialized view for query patterns and later try to evolve the base table schema; migration scripts written before the view existed; confusion because secondary indexes are checked per-column but materialized views block all column drops on the base table.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java:516

                return;
            }

            if (currentColumn.isPrimaryKeyColumn())
                throw ire("Cannot drop PRIMARY KEY column %s", column);

            /*
             * Cannot allow dropping top-level columns of user defined types that aren't frozen because we cannot convert
             * the type into an equivalent tuple: we only support frozen tuples currently. And as such we cannot persist
             * the correct type in system_schema.dropped_columns.
             */
            if (currentColumn.type.isUDT() && currentColumn.type.isMultiCell())
                throw ire("Cannot drop non-frozen column %s of user type %s", column, currentColumn.type.asCQL3Type());

            if (!table.indexes.isEmpty())
                AlterTableStatement.validateIndexesForColumnModification(table, column, false);

            if (!isEmpty(keyspace.views.forTable(table.id)))
                throw ire("Cannot drop column %s on base table %s with materialized views", currentColumn, table.name);

            builder.removeRegularOrStaticColumn(column);
            builder.recordColumnDrop(currentColumn, getTimestamp());
        }

        /**
         * @return timestamp from query, otherwise return current time in micros
         */
        private long getTimestamp()
        {
            // Prior to Metadata serialization V5, the execution timestamp was not included in AlterSchema
            // serializations. Instead, the current time (from ClientState::getTimestamp) was used, making
            // DROP COLUMN non-idempotent and causing potenial data loss as described in CASSANDRA-18961.
            // This was fixed before release by serialization V5, but we include a dangerous backwards
            // compatibility option here or so that we can still apply pre-V5 serialized transformations
            // (which would only exist in clusters running pre-release versions of Cassandra). Once all peers
            // are running a V5 compatible version, ClientState::getTimestamp will never be used.
            return timestamp == null ? fixedTimestampMicros().orElseGet(ClientState::getTimestamp) : timestamp;

View on GitHub (pinned to 88fd0f6a0e)