{"record":{"id":"0b0329b503297af2","repo":"apache/cassandra","slug":"serial-local-serial-consistency-may-only-be-reques","errorCode":null,"errorMessage":"SERIAL/LOCAL_SERIAL consistency may only be requested for one partition at a time","messagePattern":"SERIAL/LOCAL_SERIAL consistency may only be requested for one partition at a time","errorType":"exception","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/StorageProxy.java","lineNumber":2353,"sourceCode":"            List<PartitionIterator> partitionIterators = new ArrayList<>(numQueries);\n            for (int i = 0; i < numQueries; i++)\n                partitionIterators.add(null);\n            for (Map.Entry<Integer, TxnDataValue> e : data.entrySet())\n            {\n                int queryIndex = e.getKey();\n                TxnDataKeyValue value = ((TxnDataKeyValue)e.getValue());\n                partitionIterators.set(queryIndex, singletonIterator(value.rowIterator(isQueryReversed.test(queryIndex))));\n            }\n            return serialReadResult(partitionIterators.size() == 1 ? partitionIterators.get(0) : PartitionIterators.concat(partitionIterators));\n        }\n    }\n\n    private static ConsensusAttemptResult legacyReadWithPaxos(SinglePartitionReadCommand.Group group, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime)\n    throws InvalidRequestException, UnavailableException, ReadFailureException, ReadTimeoutException\n    {\n        long start = nanoTime();\n        if (group.queries.size() > 1)\n            throw new InvalidRequestException(\"SERIAL/LOCAL_SERIAL consistency may only be requested for one partition at a time\");\n\n        SinglePartitionReadCommand command = group.queries.get(0);\n        TableMetadata metadata = command.metadata();\n        DecoratedKey key = command.partitionKey();\n        // calculate the blockFor before repair any paxos round to avoid RS being altered in between.\n        int blockForRead = consistencyLevel.blockFor(Keyspace.open(metadata.keyspace).getReplicationStrategy());\n\n        try\n        {\n            final ConsistencyLevel consistencyForReplayCommitsOrFetch = consistencyLevel.isDatacenterLocal()\n                                                                        ? ConsistencyLevel.LOCAL_QUORUM\n                                                                        : ConsistencyLevel.QUORUM;\n\n            try\n            {\n                // Commit an empty update to make sure all in-progress updates that should be finished first is, _and_\n                // that no other in-progress can get resurrected.\n                Function<Ballot, Pair<PartitionUpdate, RowIterator>> updateProposer =","sourceCodeStart":2335,"sourceCodeEnd":2371,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/StorageProxy.java#L2335-L2371","documentation":"InvalidRequestException from legacyReadWithPaxos: serial (LWT/Paxos) reads support only a single partition per request because Paxos rounds are per-partition. Passing a read group with more than one query is rejected before any protocol work starts.","triggerScenarios":"Issuing a SERIAL or LOCAL_SERIAL read whose SinglePartitionReadCommand.Group contains >1 query — i.e., a serial read that spans multiple partitions (e.g., multi-partition IN clause read with serial consistency through StorageProxy.read with serial consistency level).","commonSituations":"Driver-built batched/multi-partition SELECT with consistency SERIAL; migrating thrift-era multi-get to serial reads; IN queries on the partition key with SERIAL consistency.","solutions":["Issue one serial read per partition (loop over keys, one query each).","Drop the serial consistency for the multi-partition read if linearizability across partitions is not required.","Restructure the data model so the operations needing serial consistency fit in one partition."],"exampleFix":"// before\n// SELECT ... WHERE pk IN (?, ?) with consistency SERIAL\n// after\nfor (Object pk : keys) {\n    SimpleStatement st = SimpleStatement.builder(\"SELECT * FROM ks.t WHERE pk=?\").setPositionalArgs(pk)\n        .setSerialConsistencyLevel(ConsistencyLevel.SERIAL).build();\n    session.execute(st);\n}","handlingStrategy":"validation","validationCode":"if (keys.size() > 1 && serialConsistency) {\n    throw new IllegalArgumentException(\"SERIAL reads must target a single partition\");\n}","typeGuard":null,"tryCatchPattern":"catch (InvalidRequestException e) {\n    if (e.getMessage().contains(\"one partition at a time\")) {\n        return keys.stream().map(k -> executeSerialRead(k)).collect(toList());\n    }\n    throw e;\n}","preventionTips":["Never use IN/multi-partition selects with SERIAL/LOCAL_SERIAL consistency.","Build driver statements one partition per serial read.","Design LWT partitions so transactional needs fit one partition.","Add a unit test asserting serial reads use a single partition key."],"tags":["cassandra","lwt","paxos","serial-consistency"],"backgroundTag":"invalid-argument-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}