apache/cassandra · warning
Aggregation query used on multiple partition keys (IN…
Error message
Aggregation query used on multiple partition keys (IN restriction)
What it means
Aggregation with an IN restriction on the partition key aggregates across multiple partitions in one coordinator operation. Cassandra warns the client because cost grows linearly with the number of partition keys in the IN list.
Solutions
- Issue one aggregation query per partition key and sum client-side
- Reduce the IN list size or fan out queries in parallel
- Precompute counts with counters or an aggregate table
- Use analytics tooling for multi-partition aggregation
Example fix
// before SELECT count(*) FROM sensor_data WHERE device_id IN (1,2,3,4,5); // after SELECT count(*) FROM sensor_data WHERE device_id = 1; // repeat per device, sum client-side
Defensive patterns
Strategy: validation
Validate before calling
if (isAggregate(cql) && cql.matches(".*IN\\s*\\(.*")) {
throw new IllegalArgumentException("aggregate with IN on partition key not allowed; fan out per key");
} Prevention
- Cap IN list sizes in query builders
- Fan out per-partition aggregate queries in parallel
- Precompute multi-partition aggregates in tables
When it happens
Trigger: `SELECT count(*) FROM ks.tbl WHERE pk IN (k1, k2, ..., kN)` with N > 1; SelectStatement.execute detects restrictions.keyIsInRelation() for an aggregating query and warns.
Common situations: Dashboard queries counting across a handful of known partitions; batch report jobs issuing large IN lists; gradual growth of IN lists until scans become slow.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- Aggregation query used without partition key
- Unlogged batch covering
- aggregate functions cannot be used as arguments of…
- <dynamic warning, no literal in source: built by…
- Guardrail violated
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/0b6d9547fe1e1e65.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/SelectStatement.java:627
long nowInSec,
int userLimit,
AggregationSpecification aggregationSpec,
Dispatcher.RequestTime requestTime,
boolean unmask)
{
Guardrails.pageSize.guard(pageSize, table(), false, state.getClientState());
if (aggregationSpecFactory != null)
{
if (!restrictions.hasPartitionKeyRestrictions())
{
warn("Aggregation query used without partition key");
noSpamLogger.warn(String.format("Aggregation query used without partition key on table %s.%s, aggregation type: %s",
keyspace(), table(), aggregationSpec.kind()));
}
else if (restrictions.keyIsInRelation())
{
warn("Aggregation query used on multiple partition keys (IN restriction)");
noSpamLogger.warn(String.format("Aggregation query used on multiple partition keys (IN restriction) on table %s.%s, aggregation type: %s",
keyspace(), table(), aggregationSpec.kind()));
}
}
// We can't properly do post-query ordering if we page (see #6722)
// For GROUP BY or aggregation queries we always page internally even if the user has turned paging off
checkFalse(pageSize > 0 && needsPostQueryOrdering(),
"Cannot page queries with both ORDER BY and a IN restriction on the partition key;"
+ " you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query");
ResultMessage.Rows msg;
try (PartitionIterator page = pager.fetchPage(pageSize, requestTime))
{
msg = processResults(page, options, selectors, nowInSec, userLimit, aggregationSpec, unmask, state.getClientState());
}
// Please note that the isExhausted state of the pager only gets updated when we've closed the page, so thisView on GitHub (pinned to 88fd0f6a0e)