apache/cassandra · error · InvalidRequestException

Within a transaction, SELECT statements must select a single

Error message

Within a transaction, SELECT statements must select a single partition; found <N> partitions

What it means

Within a transaction (TransactionStatement), every SELECT must resolve to exactly one partition. createNamedRead casts the select's query to a SinglePartitionReadQuery.Group and throws InvalidRequestException when the group contains more than one partition read command, because transactional reads must target a single partition key.

Source

Thrown at src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java:278

            return stream.iterator();
        };
    }

    @Override
    public ResultSet.ResultMetadata getResultMetadata()
    {
        return resultMetadata;
    }

    TxnNamedRead createNamedRead(NamedSelect namedSelect, QueryOptions options, TableMetadatasAndKeys.KeyCollector keyCollector)
    {
        SelectStatement select = namedSelect.select;
        // We reject reads from both LET and SELECT that do not specify a single row.
        @SuppressWarnings("unchecked")
        SinglePartitionReadQuery.Group<SinglePartitionReadCommand> selectQuery = (SinglePartitionReadQuery.Group<SinglePartitionReadCommand>) select.getQuery(options, 0);

        if (selectQuery.queries.size() != 1)
            throw invalidRequest("Within a transaction, SELECT statements must select a single partition; found " + selectQuery.queries.size() + " partitions");

        SinglePartitionReadCommand command = Iterables.getOnlyElement(selectQuery.queries);
        return new TxnNamedRead(namedSelect.name, keyCollector.collect(command.metadata(), command.partitionKey()), command, keyCollector.tables);
    }

    List<TxnNamedRead> createNamedReads(NamedSelect namedSelect, QueryOptions options, TableMetadatasAndKeys.KeyCollector keyCollector)
    {
        SelectStatement select = namedSelect.select;
        // We reject reads from both LET and SELECT that do not specify a single row.
        @SuppressWarnings("unchecked")
        SinglePartitionReadQuery.Group<SinglePartitionReadCommand> selectQuery = (SinglePartitionReadQuery.Group<SinglePartitionReadCommand>) select.getQuery(options, 0);

        if (selectQuery.queries.size() == 1)
            return Collections.singletonList(new TxnNamedRead(namedSelect.name, keyCollector.collect(select.table, selectQuery.queries.get(0).partitionKey()), selectQuery.queries.get(0), keyCollector.tables));

        List<TxnNamedRead> list = new ArrayList<>(selectQuery.queries.size());
        for (int i = 0; i < selectQuery.queries.size(); i++)
        {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Add an equality predicate on the full partition key to the transaction's SELECT
  2. Remove IN clauses spanning multiple partition keys; issue one transaction per partition
  3. Restructure the workload so each transaction reads rows from a single partition

Example fix

// before
SELECT * FROM t WHERE pk IN (1, 2); -- within transaction: 2 partitions
// after
SELECT * FROM t WHERE pk = 1; -- single partition
Defensive patterns

Strategy: validation

Validate before calling

// ensure the WHERE clause pins the partition key before running a transaction
boolean singlePartition = whereClause.matches(".*pk\s*=\s*[^I].*") && !whereClause.toUpperCase().contains(" IN ");
if (!singlePartition) throw new IllegalArgumentException("transactional SELECT must target one partition");

Try / catch

try { session.execute(txnStatement); }
catch (InvalidRequestException e) { if (e.getMessage().contains("single partition")) { /* split into per-partition transactions */ } }

Prevention

When it happens

Trigger: Running a transaction whose named SELECT (via LET or SELECT) has WHERE clauses that do not constrain the read to a single partition — e.g. missing the partition key equality predicate or using IN across multiple partition keys.

Common situations: Omitting the full primary key from the WHERE clause; using IN with multiple partition keys in a transactional SELECT; using ALLOW FILTERING-style ranges inside a transaction.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/a7452f46a082c1d1. Report an issue: GitHub.