apache/cassandra · error · InvalidRequestException

Cannot provide custom timestamp for counter BATCH

Error message

Cannot provide custom timestamp for counter BATCH

What it means

Counter mutations have no user-settable writetime (they use server-side counters), so a counter batch may not include USING TIMESTAMP. BatchStatement.validate() throws this InvalidRequestException when timestampSet && isCounter().

Source

Thrown at src/java/org/apache/cassandra/cql3/statements/BatchStatement.java:265

        ModificationStatement.TableAuthorizationState authorizationState = new ModificationStatement.TableAuthorizationState();
        for (ModificationStatement statement : statements)
            statement.authorize(state, authorizationState);
    }

    // Validates a prepared batch statement without validating its nested statements.
    public void validate() throws InvalidRequestException
    {
        if (attrs.isTimeToLiveSet())
            throw new InvalidRequestException("Global TTL on the BATCH statement is not supported.");

        boolean timestampSet = attrs.isTimestampSet();
        if (timestampSet)
        {
            if (hasConditions)
                throw new InvalidRequestException("Cannot provide custom timestamp for conditional BATCH");

            if (isCounter())
                throw new InvalidRequestException("Cannot provide custom timestamp for counter BATCH");
        }

        boolean hasCounters = false;
        boolean hasNonCounters = false;

        boolean hasVirtualTables = false;
        boolean hasRegularTables = false;

        for (ModificationStatement statement : statements)
        {
            if (timestampSet && statement.isTimestampSet())
                throw new InvalidRequestException("Timestamp must be set either on BATCH or individual statements: " + statement.source);

            if (statement.isCounter())
                hasCounters = true;
            else
                hasNonCounters = true;

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Remove USING TIMESTAMP from the counter batch
  2. If timestamp control is required, use regular (non-counter) tables instead of counters

Example fix

// before
BEGIN BATCH USING TIMESTAMP 1234 UPDATE counters SET c = c + 1 WHERE k = 'a'; APPLY BATCH;
// after
BEGIN BATCH UPDATE counters SET c = c + 1 WHERE k = 'a'; APPLY BATCH;
Defensive patterns

Strategy: validation

Validate before calling

boolean isCounterBatch = statements.stream().allMatch(BatchStatement::isCounter);
if (isCounterBatch && batchUsesTimestamp) throw new IllegalArgumentException("USING TIMESTAMP not allowed on counter batches");

Try / catch

try { session.execute(batch); }
catch (InvalidQueryException e) {
    if (e.getMessage().contains("custom timestamp for counter BATCH")) { /* strip USING TIMESTAMP */ }
}

Prevention

When it happens

Trigger: BEGIN BATCH ... USING TIMESTAMP n ... where all statements target counter tables (isCounter() true), executed directly or via prepare.

Common situations: Reusing a generic write helper that always sets timestamps on batches; migrating regular-column writes to counters without stripping USING TIMESTAMP.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/4d6b4f8e163baef7. Report an issue: GitHub.