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
- Add a WHERE clause that pins the partition key to a single value, e.g. `WHERE txn_id = '<txnId>'`.
- Iterate over known txn ids client-side, issuing one single-partition query per id.
- 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
- Always include an equality predicate on the partition key when querying accord debug tables.
- Never rely on full scans of these debug tables.
- Iterate txn ids client-side issuing one single-partition query each.
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
- Cannot filter this table by partial partition key
- COMMAND_STORE_OPS + " is a write-only table"
- metadata + " currently only supports querying single…
- metadata + " does not support filtering by token or…
- Must specify full partition key bounds for the underlying…
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)