apache/cassandra · error · InvalidRequestException
Range deletions must specify a complete partition key in…
Error message
Range deletions must specify a complete partition key in the underlying table
What it means
Range tombstones in an UPDATE against the virtual table are translated back into partitions of the underlying remote table. A range deletion whose clustering bounds cover fewer than the full partition key of the underlying table cannot be mapped to an exact partition key, so it is rejected with InvalidRequestException.
Solutions
- Delete by exact, full primary key of the virtual table (equality on all primary key columns).
- Use a partition-level delete if you intend to remove an entire underlying partition.
- Rewrite the deletion as explicit per-row DELETEs for each key to remove.
- Avoid range predicates in DELETE on this virtual table.
Example fix
// before DELETE FROM vt WHERE clustering_col < 10; // range tombstone // after DELETE FROM vt WHERE pk = ... AND clustering_col = 5; // exact row delete
Defensive patterns
Strategy: validation
Validate before calling
// Ensure deletes are exact-key
if (deleteStatement.hasRangePredicate())
throw new IllegalArgumentException("Range deletes unsupported; delete by full primary key"); Try / catch
try { session.execute(delete); }
catch (InvalidRequestException e) {
if (e.getMessage().contains("complete partition key"))
// convert to per-row exact deletes
}
Prevention
- Always DELETE with full primary key equality
- Avoid range predicates in DELETE on virtual tables
- Use partition-level or truncate semantics for bulk removal
- Review batch statements for generated range tombstones
When it happens
Trigger: DELETE ... WHERE clustering-col range / USING TTL batch that produces a range tombstone whose deletedSlice().start() or end() has fewer components than the underlying table's partition key count (pkCount).
Common situations: DELETE with a range predicate (e.g. clustering_col < X) on the virtual table where the underlying table's partition key is derived from remote clustering columns; accidental multi-row range deletes.
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
- Range deletions must specify a single partition key in the…
- Can only unset '" + name + "'
- Cannot filter this table by partial partition key
- Cannot set bucket_sub_size to zero.
- Cannot update '" + name + "'
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/6dbe997aad21574e.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/virtual/RemoteToLocalVirtualTable.java:530
{
int ckCount = local.clusteringColumns().size();
pkBuffer = pkCount == 1 ? null : new ByteBuffer[pkCount];
ckBuffer = new ByteBuffer[ckCount];
}
PartitionUpdate.Builder builder = null;
ArrayDeque<Promise<Void>> results = new ArrayDeque<>();
if (deletionInfo.hasRanges())
{
Iterator<RangeTombstone> iterator = deletionInfo.rangeIterator(false);
while (iterator.hasNext())
{
RangeTombstone rt = iterator.next();
ClusteringBound start = rt.deletedSlice().start();
ClusteringBound end = rt.deletedSlice().end();
if (start.size() < pkCount || end.size() < pkCount)
throw new InvalidRequestException("Range deletions must specify a complete partition key in the underlying table " + metadata);
for (int i = 0 ; i < pkCount ; ++i)
{
if (0 != start.accessor().compare(start.get(i), end.get(i), end.accessor()))
throw new InvalidRequestException("Range deletions must specify a single partition key in the underlying table " + metadata);
}
DecoratedKey key = remoteClusteringToLocalPartitionKey(local, start, pkCount, pkBuffer);
builder = maybeRolloverAndWait(key, builder, results, endpoint);
if (start.size() == pkCount && end.size() == pkCount)
{
builder.addPartitionDeletion(rt.deletionTime());
}
else
{
start = ClusteringBound.create(start.kind(), Clustering.make(remoteClusteringToLocalClustering(start.clustering(), pkCount, ckBuffer)));
end = ClusteringBound.create(end.kind(), Clustering.make(remoteClusteringToLocalClustering(end.clustering(), pkCount, ckBuffer)));
builder.add(new RangeTombstone(Slice.make(start, end), rt.deletionTime()));View on GitHub (pinned to 88fd0f6a0e)