apache/druid · error · UnsupportedOperationException
Cannot operate on a dimension with unknown cardinality
Error message
Cannot operate on a dimension with unknown cardinality
What it means
In PooledTopNAlgorithm.scanAndAggregateDefault, params.getCardinality() must be non-negative because the default scan path indexes directly into a positions array sized by dimension cardinality. A negative cardinality (dimension with unknown/no dictionary) makes indexed aggregation impossible, so UnsupportedOperationException is thrown. This guards the aggregation loop against out-of-range indexing into per-value slots.
Source
Thrown at processing/src/main/java/org/apache/druid/query/topn/PooledTopNAlgorithm.java:498
* See http://en.wikipedia.org/wiki/Duff's_device for more information on this kind of approach
*
* This allows out of order execution of the code. In local tests, the JVM inlines all the way to this function.
*
* If there are more than AGG_UNROLL_COUNT aggregates, then the remainder is calculated with the switch, and the
* blocks of AGG_UNROLL_COUNT are calculated in a partially unrolled for-loop.
*
* Putting the switch first allows for optimization for the common case (less than AGG_UNROLL_COUNT aggs) but
* still optimizes the high quantity of aggregate queries which benefit greatly from any speed improvements
* (they simply take longer to start with).
*/
private static long scanAndAggregateDefault(
final PooledTopNParams params,
final int[] positions,
final BufferAggregator[] theAggregators
)
{
if (params.getCardinality() < 0) {
throw new UnsupportedOperationException("Cannot operate on a dimension with unknown cardinality");
}
final ByteBuffer resultsBuf = params.getResultsBuf();
final int numBytesPerRecord = params.getNumBytesPerRecord();
final int[] aggregatorSizes = params.getAggregatorSizes();
final Cursor cursor = params.getCursor();
final CursorGranularizer granularizer = params.getGranularizer();
final DimensionSelector dimSelector = params.getDimSelector();
final int[] aggregatorOffsets = new int[aggregatorSizes.length];
for (int j = 0, offset = 0; j < aggregatorSizes.length; ++j) {
aggregatorOffsets[j] = offset;
offset += aggregatorSizes[j];
}
final int aggSize = theAggregators.length;
final int aggExtra = aggSize % AGG_UNROLL_COUNT;
int currentPosition = 0;View on GitHub (pinned to 9b90983fd2)
Solutions
- Use a dictionary-encoded string dimension for topN
- Convert the query to groupBy, which handles unknown cardinality
- Verify the segment is not being swapped/unmapped mid-query; retry the query
- Check ingestion config so the dimension column is dictionary-encoded
Example fix
// before
topN over non-dictionary dimension -> UnsupportedOperationException
// after
GroupByQuery.newBuilder().setDimension(new DefaultDimensionSpec("country", "country"))... Defensive patterns
Strategy: validation
Validate before calling
if (params.getCardinality() < 0) { /* use groupBy fallback before scanAndAggregateDefault */ } Type guard
boolean supportsPooledTopN(PooledTopNParams params) {
return params.getCardinality() >= 0;
} Try / catch
try {
result = algorithm.run(params);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("unknown cardinality")) { /* rerun as groupBy */ }
throw e;
} Prevention
- Ensure the topN dimension column is dictionary-encoded at ingestion
- Fallback to groupBy when selector cardinality is unknown
- Avoid topN over datasources whose segments can be swapped mid-query
When it happens
Trigger: TopN query falling back to scanAndAggregateDefault while the PooledTopNParams carries cardinality < 0 — a dimension selector with unknown cardinality, or params built without a valid cardinality (e.g. after init skipped validation or cardinality changed between init and scan).
Common situations: Querying segments where the chosen dimension lacks dictionary encoding; race between segment replacement/unmapping and query execution leaving stale params; using topN against data sources that don't dictionary-encode the dimension.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot operate on a dimension with no dictionary
- Unknown type[%s] for metric[%s]
- Null cursor factory found. Probably trying to issue a query
- Query type '%s' does not support returning results as arrays
- Can't find the topN metric
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/688166968919ea48.
Report an issue: GitHub.