apache/cassandra · error · InvalidRequestException

Cannot CREATE TRIGGER for a materialized view

Error message

Cannot CREATE TRIGGER for a materialized view

What it means

Thrown while applying CREATE TRIGGER when the target relation resolved via getTableOrViewNullable() is a materialized view rather than a base table. Triggers may only be attached to base tables; views are maintained automatically by the system, so the statement is rejected.

Solutions

  1. Target the base table that backs the materialized view instead
  2. Drop the trigger DDL if triggers on the view were never valid
  3. Rename or disambiguate so the statement clearly references the base table

Example fix

// before
CREATE TRIGGER trg ON ks.orders_by_day USING 'com.example.Trig'; -- materialized view
// after
CREATE TRIGGER trg ON ks.orders USING 'com.example.Trig'; -- base table
Defensive patterns

Strategy: validation

Validate before calling

const v = await session.execute("SELECT table_name FROM system_schema.views WHERE keyspace_name = ? AND view_name = ?", [ks, table]);
if (v.rows.length > 0) throw new Error(`${ks}.${table} is a materialized view; triggers are not supported`);

Try / catch

try { session.execute(triggerDdl); } catch (e) { if (/materialized view/.test(e.message)) { /* retarget the base table */ } else throw e; }

Prevention

When it happens

Trigger: CREATE TRIGGER trg ON ks.some_materialized_view USING 'cls'; — the name resolves to a view rather than a base table.

Common situations: View and base table sharing similar names and the wrong one was picked; refactoring where a table was replaced by a materialized view while trigger DDL still targets the old name.

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/042a69d340fd0459. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateTriggerStatement.java:92

    public boolean compatibleWith(ClusterMetadata metadata)
    {
        return metadata.directory.commonSerializationVersion.isAtLeast(Version.V0);
    }

    @Override
    public Keyspaces apply(ClusterMetadata metadata)
    {
        Keyspaces schema = metadata.schema.getKeyspaces();
        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
        if (null == keyspace)
            throw ire("Keyspace '%s' doesn't exist", keyspaceName);

        TableMetadata table = keyspace.getTableOrViewNullable(tableName);
        if (null == table)
            throw ire("Table '%s' doesn't exist", tableName);

        if (table.isView())
            throw ire("Cannot CREATE TRIGGER for a materialized view");

        TriggerMetadata existingTrigger = table.triggers.get(triggerName).orElse(null);
        if (null != existingTrigger)
        {
            if (ifNotExists)
                return schema;

            throw ire("Trigger '%s' already exists", triggerName);
        }

        try
        {
            TriggerExecutor.instance.loadTriggerClass(triggerClass);
        }
        catch (Exception e)
        {
            logger.warn(String.format("Trigger class '%s' couldn't be loaded at apply stage.", triggerClass));
        }

View on GitHub (pinned to 88fd0f6a0e)