apache/cassandra · error · InvalidRequestException

Timestamp must be set either on BATCH or individual statemen

Error message

Timestamp must be set either on BATCH or individual statements: 

What it means

When a batch-level USING TIMESTAMP is set, none of the individual statements may also set their own USING TIMESTAMP — the source of the write timestamp must be unambiguous. BatchStatement.validate() throws this InvalidRequestException naming the offending statement.

Source

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

        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;

            if (statement.isVirtual())
                hasVirtualTables = true;
            else
                hasRegularTables = true;
        }

        if (timestampSet && hasCounters)
            throw new InvalidRequestException("Cannot provide custom timestamp for a BATCH containing counters");

        if (isCounter() && hasNonCounters)
            throw new InvalidRequestException("Cannot include non-counter statement in a counter batch");

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Remove USING TIMESTAMP from the individual statement named in the error, keeping the batch-level timestamp
  2. Or remove the batch-level USING TIMESTAMP and keep per-statement timestamps

Example fix

// before
BEGIN BATCH USING TIMESTAMP 1000 INSERT INTO t (k,v) VALUES (1,'x') USING TIMESTAMP 2000; APPLY BATCH;
// after
BEGIN BATCH USING TIMESTAMP 1000 INSERT INTO t (k,v) VALUES (1,'x'); APPLY BATCH;
Defensive patterns

Strategy: validation

Validate before calling

if (batchUsesTimestamp && statements.stream().anyMatch(ModificationStatement::isTimestampSet))
    throw new IllegalArgumentException("timestamp set both on BATCH and a child statement");

Try / catch

try { session.execute(batch); }
catch (InvalidQueryException e) {
    if (e.getMessage().startsWith("Timestamp must be set either on BATCH")) { /* pick one level for the timestamp */ }
}

Prevention

When it happens

Trigger: BEGIN BATCH USING TIMESTAMP n containing at least one statement whose isTimestampSet() is true (statement.timestamp reported in the message), via execute or prepare.

Common situations: Application code that appends USING TIMESTAMP to every INSERT while a batching layer also adds a batch-level timestamp; hand-written batches converted from single-statement templates.

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/14e443ac4176079d. Report an issue: GitHub.