apache/cassandra · error · InvalidRequestException

metadata + " only supports single partition key queries"

Error message

metadata + " only supports single partition key queries"

What it means

This accord debug virtual table (e.g. the txn-ops/journal dump table) implements collect() via collector.singlePartitionKey(), which returns non-null only when the query is restricted to exactly one partition key. Queries without a partition key constraint (full scans, or multi-partition IN queries) throw InvalidRequestException.

Solutions

  1. Add a WHERE clause that pins the partition key to a single value, e.g. `WHERE txn_id = '<txnId>'`.
  2. Iterate over known txn ids client-side, issuing one single-partition query per id.
  3. Use depth/execute_at filters only as additional constraints on top of the single-partition key.

Example fix

// before
SELECT * FROM system_views.accord_txn_ops;
// after
SELECT * FROM system_views.accord_txn_ops WHERE txn_id = '<txnId>';
Defensive patterns

Strategy: validation

Validate before calling

// Enforce single-partition reads on accord debug tables
String where = extractWhereClause(query);
if (where == null || !where.matches(".*txn_id\s*=\s*'[^']+'.*"))
    throw new IllegalArgumentException("accord debug tables require a single partition key equality predicate");

Try / catch

try {
    session.execute(query);
} catch (InvalidRequestException e) {
    if (e.getMessage().contains("only supports single partition key queries")) {
        // rewrite the query with WHERE txn_id = '<id>'
    }
}

Prevention

When it happens

Trigger: Running `SELECT * FROM <table>;` or a multi-partition query against the accord debug table without a WHERE clause pinning the partition key (e.g. txn_id) to a single value.

Common situations: Exploratory browsing of the debug table without knowing a txn id; dashboards attempting full-table scans; assuming virtual tables support unrestricted reads.

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/610b58d580e66778. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/db/virtual/AccordDebugKeyspace.java:2136

    static abstract class AbstractTxnGraphTable extends AbstractLazyVirtualTable
    {
        protected AbstractTxnGraphTable(TableMetadata metadata, OnTimeout onTimeout, Sorted sorted)
        {
            super(metadata, onTimeout, sorted);
        }

        protected AbstractTxnGraphTable(TableMetadata metadata, OnTimeout onTimeout, Sorted sorted, Sorted sortedByPartitionKey)
        {
            super(metadata, onTimeout, sorted, sortedByPartitionKey);
        }

        @Override
        protected void collect(PartitionsCollector collector)
        {
            Object[] pks = collector.singlePartitionKey();
            if (pks == null)
                throw new InvalidRequestException(metadata + " only supports single partition key queries");

            FilterRange<Integer> depthRange = collector.filters("depth", Function.identity(), i -> i + 1, i -> i - 1);
            int maxDepth = depthRange.max == null ? Integer.MAX_VALUE : depthRange.max;

            // TODO (expected): cleanly handle Timestamp.NONE / Timestamp.MAX
            FilterRange<String> executeAtRange = collector.filters("execute_at", Function.identity(), i -> Timestamp.parse(i).next().toString(), i -> Timestamp.parse(i).prev().toString());
            FilterRange<String> parentRange = collector.filters("parent", Function.identity(), i -> Timestamp.parse(i).next().toString(), i -> Timestamp.parse(i).prev().toString());
            Timestamp min = Timestamp.nonNullOrMax(Timestamp.nonNullOrMax(executeAtRange == null ? null : executeAtRange.min == null ? null : Timestamp.tryParse(executeAtRange.min), parentRange == null ? null : parentRange.min == null ? null : Timestamp.tryParse(parentRange.min)), Timestamp.NONE);


            TxnKindsAndDomains kinds;
            Participants<?> intersects;
            {
                TxnKindsAndDomains tmpKinds = TxnKindsAndDomains.ALL;
                Participants<?> tmpIntersects = null;
                for (RowFilter.Expression expr : collector.rowFilter().getExpressions())
                {
                    if (expr.isCustom())

View on GitHub (pinned to 88fd0f6a0e)