apache/cassandra · error · InvalidRequestException
Counter mutations and trigger mutations cannot be applied…
Error message
Counter mutations and trigger mutations cannot be applied together atomically.
What it means
TriggerExecutor executes user-defined triggers that can augment the original mutations with additional ones. If the original statement contains counter mutations (PartitionUpdates with counters) and the trigger also produced augmented mutations, the two cannot be applied atomically, so the executor rejects the request with InvalidRequestException instead of applying them partially.
Solutions
- Remove the trigger from the counter table (DROP TRIGGER)
- Split the operation so counter writes and trigger-augmented non-counter writes are issued as separate statements
- Redesign the trigger to only apply to non-counter tables, or replace the trigger with application-level writes
Example fix
// before // trigger on counter table + counter update UPDATE counters SET votes = votes + 1 WHERE pk = 1; // rejected // after DROP TRIGGER audit_trg ON counters; UPDATE counters SET votes = votes + 1 WHERE pk = 1;
Defensive patterns
Strategy: try-catch
Validate before calling
// before executing: check table has counters and a trigger
if (tableMeta.hasCounterColumns() && tableMeta.getTriggers().size() > 0) throw new IllegalStateException('Trigger on counter table is not allowed'); Try / catch
catch InvalidRequestException with message containing 'Counter mutations and trigger mutations' and surface a config error to the operator
Prevention
- Never create triggers on counter tables
- Audit schema for triggers with `SELECT * FROM system_schema.triggers;`
- Split counter and non-counter writes into separate statements
When it happens
Trigger: An INSERT/UPDATE/BATCH touching counter columns on a table that also has a trigger defined, where the trigger's execute() returns non-null augmented mutations.
Common situations: Adding a trigger to an existing counter table; running a batch mixing counter and non-counter writes on a triggered table; migrating an application that used triggers for audit writes onto counter tables.
Related errors
- Partition key of additional mutation does not match primary…
- table of additional mutation does not match primary update…
- The updates generated by triggers are not all for the same…
- Triggers are present but TriggersPolicy.forbidden is…
- A storage-attached index cannot be created over multiple…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/f89ffdea25c430dd.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/triggers/TriggerExecutor.java:159
for (PartitionUpdate upd : mutation.getPartitionUpdates())
{
List<Mutation> augmentations = executeInternal(upd);
if (augmentations == null || augmentations.isEmpty())
continue;
validate(augmentations);
if (augmentedMutations == null)
augmentedMutations = new LinkedList<>();
augmentedMutations.addAll(augmentations);
}
}
if (augmentedMutations == null)
return null;
if (hasCounters)
throw new InvalidRequestException("Counter mutations and trigger mutations cannot be applied together atomically.");
@SuppressWarnings("unchecked")
Collection<Mutation> originalMutations = (Collection<Mutation>) mutations;
return mergeMutations(Iterables.concat(originalMutations, augmentedMutations));
}
private List<Mutation> mergeMutations(Iterable<Mutation> mutations)
{
ListMultimap<Pair<String, ByteBuffer>, Mutation> groupedMutations = ArrayListMultimap.create();
for (Mutation mutation : mutations)
{
Pair<String, ByteBuffer> key = Pair.create(mutation.getKeyspaceName(), mutation.key().getKey());
groupedMutations.put(key, mutation);
}
List<Mutation> merged = new ArrayList<>(groupedMutations.size());View on GitHub (pinned to 88fd0f6a0e)