apache/cassandra · error · TriggerDisabledException
Triggers are present but TriggersPolicy.forbidden is…
Error message
Triggers are present but TriggersPolicy.forbidden is configured. Failing query that would execute triggers: %s
What it means
When cassandra.yaml sets triggers_policy: forbidden, any statement that would execute triggers (a table with triggers present) is failed outright with TriggerDisabledException, embedding the list of triggers that would have run. Unlike the 'disabled' policy (which silently skips triggers and logs a warning), 'forbidden' treats executing such a statement as an error to surface misconfiguration.
Solutions
- Remove the triggers from the affected tables (DROP TRIGGER) since policy forbids them
- Change cassandra.yaml to triggers_policy: enabled (or disabled) and restart the node if triggers are still required
- Update the application to stop relying on triggers and perform the equivalent writes explicitly
Example fix
// before (cassandra.yaml) triggers_policy: forbidden // after triggers_policy: enabled
Defensive patterns
Strategy: try-catch
Validate before calling
// before writes: check cluster policy and table triggers
String policy = config.get('triggers_policy');
boolean hasTriggers = schema.getTriggers(table).size() > 0;
if ('forbidden'.equals(policy) && hasTriggers) throw new IllegalStateException('Writes to ' + table + ' will fail: triggers_policy=forbidden'); Try / catch
catch TriggerDisabledException (or InvalidRequestException wrapping it), then retry after dropping the trigger or changing policy
Prevention
- Keep triggers_policy consistent across environments
- Audit tables for triggers before setting policy to forbidden
- Plan trigger removal before hardening cluster config
When it happens
Trigger: A write (INSERT/UPDATE/BATCH) touches a table that has triggers defined while Config.TriggersPolicy is set to forbidden in cassandra.yaml; triggered via TriggerExecutor.executeInternal from intermediate/augmentations paths.
Common situations: Operators hardened a cluster by setting triggers_policy: forbidden but applications still rely on legacy triggers; environment/config drift between dev (default/disabled) and prod (forbidden); upgrading to a version where TriggersPolicy was introduced with forbidden as the chosen policy.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Refusing to load new trigger class
- Counter mutations and trigger mutations cannot be applied…
- Partition key of additional mutation does not match primary…
- Request on table . with %sttl of seconds exceeds maximum…
- table of additional mutation does not match primary update…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/0608678de52c0d3a.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/triggers/TriggerExecutor.java:249
/**
* Switch class loader before using the triggers for the column family, if
* not loaded them with the custom class loader.
*/
private List<Mutation> executeInternal(PartitionUpdate update)
{
Triggers triggers = update.metadata().triggers;
if (triggers.isEmpty())
return null;
Config.TriggersPolicy policy = DatabaseDescriptor.getTriggersPolicy();
if (policy == Config.TriggersPolicy.disabled)
{
skippedTriggerLogger.warn("Skipping execution of triggers due to configuration TriggersPolicy.disabled: {}", triggers);
return null;
}
if (policy == Config.TriggersPolicy.forbidden)
{
throw new TriggerDisabledException(String.format("Triggers are present but TriggersPolicy.forbidden is configured. Failing query that would execute triggers: %s", triggers));
}
List<Mutation> tmutations = Lists.newLinkedList();
Thread.currentThread().setContextClassLoader(customClassLoader);
String triggerClass = "";
try
{
for (TriggerMetadata td : triggers)
{
ITrigger trigger = cachedTriggers.get(td.classOption);
triggerClass = td.classOption;
if (trigger == null)
{
trigger = loadTriggerInstance(td.classOption);
cachedTriggers.put(td.classOption, trigger);
}
Collection<Mutation> temp = trigger.augment(update);
if (temp != null)
tmutations.addAll(temp);View on GitHub (pinned to 88fd0f6a0e)