apache/cassandra · error · InvalidRequestException
Batch with conditions cannot span multiple tables: %s
Error message
Batch with conditions cannot span multiple tables: %s
What it means
Batches using lightweight transactions (conditions) are only atomic within a single table. When validate() finds conditional statements targeting more than one keyspace/table, it rejects the batch, reporting the offending statement's source location.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/BatchStatement.java:318
throw new InvalidRequestException("Cannot include a counter statement in a logged batch");
if (isLogged() && hasVirtualTables)
throw new InvalidRequestException("Cannot include a virtual table statement in a logged batch");
if (hasVirtualTables && hasRegularTables)
throw new InvalidRequestException("Mutations for virtual and regular tables cannot exist in the same batch");
if (hasConditions && hasVirtualTables)
throw new InvalidRequestException("Conditional BATCH statements cannot include mutations for virtual tables");
if (hasConditions)
{
String ksName = null;
String cfName = null;
for (ModificationStatement stmt : statements)
{
if (ksName != null && (!stmt.keyspace().equals(ksName) || !stmt.table().equals(cfName)))
throw new InvalidRequestException("Batch with conditions cannot span multiple tables: " + stmt.source);
ksName = stmt.keyspace();
cfName = stmt.table();
}
}
}
private boolean isCounter()
{
return type == Type.COUNTER;
}
private boolean isLogged()
{
return type == Type.LOGGED;
}
// The batch itself will be validated in either Parsed#prepare() - for regular CQL3 batches,
// or in QueryProcessor.processBatch() - for native protocol batches.View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Restrict the conditional batch so all statements target one table (and as of the partition check, ideally one partition)
- Split into per-table conditional statements and handle cross-table coordination in the application
- Use a single denormalized table if atomic conditional updates across what are now multiple tables are required
Example fix
// before
BEGIN BATCH UPDATE users SET name='a' WHERE id=1 IF name='b';
UPDATE orders SET status='shipped' WHERE id=9 IF status='paid'; APPLY BATCH;
// after
BEGIN BATCH UPDATE users SET name='a' WHERE id=1 IF name='b'; APPLY BATCH;
UPDATE orders SET status='shipped' WHERE id=9 IF status='paid';
Defensive patterns
Strategy: validation
Validate before calling
if (batchHasConditions && stmts.stream().map(s -> s.getTable()).distinct().count() > 1)
throw new IllegalArgumentException("LWT batch must target a single table"); Try / catch
catch (InvalidRequestException e) { if (e.getMessage().startsWith("Batch with conditions cannot span multiple tables")) { splitPerTableAndRetry(); } else throw e; } Prevention
- Design conditional writes around a single (denormalized) table
- Never port multi-table SQL transactions directly to Cassandra LWT batches
When it happens
Trigger: 'BEGIN BATCH UPDATE t1 ... IF x = 1; UPDATE t2 ... IF y = 2; APPLY BATCH' where t1 and t2 are different tables (or different keyspaces).
Common situations: Multi-entity transaction attempts ported from relational databases; applications assuming CAS batches span tables.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot provide custom timestamp for conditional BATCH
- Conditional BATCH statements cannot include mutations for vi
- Invalid empty serial consistency level
- Batch with conditions cannot span multiple partitions
- Global TTL on the BATCH statement is not supported.
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/8a7484b4b39f54b0.
Report an issue: GitHub.