{"record":{"id":"f83a6c9f7ce0c517","repo":"apache/cassandra","slug":"trigger-s-already-exists","errorCode":null,"errorMessage":"Trigger '%s' already exists","messagePattern":"Trigger '(.+?)' already exists","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/CreateTriggerStatement.java","lineNumber":100,"sourceCode":"        Keyspaces schema = metadata.schema.getKeyspaces();\n        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);\n        if (null == keyspace)\n            throw ire(\"Keyspace '%s' doesn't exist\", keyspaceName);\n\n        TableMetadata table = keyspace.getTableOrViewNullable(tableName);\n        if (null == table)\n            throw ire(\"Table '%s' doesn't exist\", tableName);\n\n        if (table.isView())\n            throw ire(\"Cannot CREATE TRIGGER for a materialized view\");\n\n        TriggerMetadata existingTrigger = table.triggers.get(triggerName).orElse(null);\n        if (null != existingTrigger)\n        {\n            if (ifNotExists)\n                return schema;\n\n            throw ire(\"Trigger '%s' already exists\", triggerName);\n        }\n\n        try\n        {\n            TriggerExecutor.instance.loadTriggerClass(triggerClass);\n        }\n        catch (Exception e)\n        {\n            logger.warn(String.format(\"Trigger class '%s' couldn't be loaded at apply stage.\", triggerClass));\n        }\n\n        TableMetadata newTable = table.withSwapped(table.triggers.with(TriggerMetadata.create(triggerName, triggerClass)));\n        return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.tables.withSwapped(newTable)));\n    }\n\n    SchemaChange schemaChangeEvent(KeyspacesDiff diff)\n    {\n        return new SchemaChange(Change.UPDATED, Target.TABLE, keyspaceName, tableName);","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/CreateTriggerStatement.java#L82-L118","documentation":"A trigger with the given name is already registered on the target table. apply() finds an existing TriggerMetadata and, unless IF NOT EXISTS was specified, throws instead of silently overwriting the existing trigger definition.","triggerScenarios":"CREATE TRIGGER existing_trg ON ks.tbl USING 'cls' where ks.tbl already has a trigger named existing_trg and no IF NOT EXISTS clause; re-running non-idempotent DDL scripts.","commonSituations":"Idempotency failures in migration scripts executed twice; divergent environments where one already has the trigger; accidental reuse of a trigger name for a different class.","solutions":["Add IF NOT EXISTS: CREATE TRIGGER IF NOT EXISTS ... to make the statement idempotent","Drop the existing trigger first: DROP TRIGGER existing_trg ON ks.tbl; then recreate it","Choose a different trigger name"],"exampleFix":"// before\nCREATE TRIGGER trg ON ks.tbl USING 'com.example.Trig';\n// after\nCREATE TRIGGER IF NOT EXISTS trg ON ks.tbl USING 'com.example.Trig';","handlingStrategy":"validation","validationCode":"const ex = await session.execute(\"SELECT trigger_name FROM system_schema.triggers WHERE keyspace_name = ? AND table_name = ? AND trigger_name = ?\", [ks, table, trigger]);\nif (ex.rows.length > 0) console.log('trigger already exists, skipping or dropping first');","typeGuard":null,"tryCatchPattern":"try { session.execute(ddl); } catch (e) { if (/already exists/.test(e.message)) { /* add IF NOT EXISTS or DROP TRIGGER then retry */ } else throw e; }","preventionTips":["Use CREATE TRIGGER IF NOT EXISTS in migration scripts","Make DDL scripts idempotent","Drop and recreate triggers when the class changes"],"tags":["cql","trigger","duplicate"],"backgroundTag":"file-already-exists","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}