{"record":{"id":"6dbe997aad21574e","repo":"apache/cassandra","slug":"range-deletions-must-specify-a-complete-partition","errorCode":null,"errorMessage":"Range deletions must specify a complete partition key in the underlying table ","messagePattern":"Range deletions must specify a complete partition key in the underlying table ","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/virtual/RemoteToLocalVirtualTable.java","lineNumber":530,"sourceCode":"        {\n            int ckCount = local.clusteringColumns().size();\n            pkBuffer = pkCount == 1 ? null : new ByteBuffer[pkCount];\n            ckBuffer = new ByteBuffer[ckCount];\n        }\n\n        PartitionUpdate.Builder builder = null;\n        ArrayDeque<Promise<Void>> results = new ArrayDeque<>();\n\n        if (deletionInfo.hasRanges())\n        {\n            Iterator<RangeTombstone> iterator = deletionInfo.rangeIterator(false);\n            while (iterator.hasNext())\n            {\n                RangeTombstone rt = iterator.next();\n                ClusteringBound start = rt.deletedSlice().start();\n                ClusteringBound end = rt.deletedSlice().end();\n                if (start.size() < pkCount || end.size() < pkCount)\n                    throw new InvalidRequestException(\"Range deletions must specify a complete partition key in the underlying table \" + metadata);\n\n                for (int i = 0 ; i < pkCount ; ++i)\n                {\n                    if (0 != start.accessor().compare(start.get(i), end.get(i), end.accessor()))\n                        throw new InvalidRequestException(\"Range deletions must specify a single partition key in the underlying table \" + metadata);\n                }\n\n                DecoratedKey key = remoteClusteringToLocalPartitionKey(local, start, pkCount, pkBuffer);\n                builder = maybeRolloverAndWait(key, builder, results, endpoint);\n                if (start.size() == pkCount && end.size() == pkCount)\n                {\n                    builder.addPartitionDeletion(rt.deletionTime());\n                }\n                else\n                {\n                    start = ClusteringBound.create(start.kind(), Clustering.make(remoteClusteringToLocalClustering(start.clustering(), pkCount, ckBuffer)));\n                    end = ClusteringBound.create(end.kind(), Clustering.make(remoteClusteringToLocalClustering(end.clustering(), pkCount, ckBuffer)));\n                    builder.add(new RangeTombstone(Slice.make(start, end), rt.deletionTime()));","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/virtual/RemoteToLocalVirtualTable.java#L512-L548","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nDELETE FROM vt WHERE clustering_col < 10;   // range tombstone\n// after\nDELETE FROM vt WHERE pk = ... AND clustering_col = 5;  // exact row delete","handlingStrategy":"validation","validationCode":"// Ensure deletes are exact-key\nif (deleteStatement.hasRangePredicate())\n    throw new IllegalArgumentException(\"Range deletes unsupported; delete by full primary key\");","typeGuard":null,"tryCatchPattern":"try { session.execute(delete); }\ncatch (InvalidRequestException e) {\n    if (e.getMessage().contains(\"complete partition key\"))\n        // convert to per-row exact deletes\n}\n","preventionTips":["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"],"tags":["cassandra","virtual-table","range-tombstone","delete"],"backgroundTag":"unsupported-operation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}