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

  1. Remove the trigger from the counter table (DROP TRIGGER)
  2. Split the operation so counter writes and trigger-augmented non-counter writes are issued as separate statements
  3. 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

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


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)