apache/druid · error · UnsupportedOperationException
Limit push down when sorting by a post aggregator is not…
Error message
Limit push down when sorting by a post aggregator is not supported.
What it means
When forcing limit push down, GroupByQuery does not support an orderBy column that refers to a post-aggregator. The sort column must be a dimension or aggregator output; sorting by a post-aggregation value cannot be pushed into the group-by engine, so an UnsupportedOperationException is thrown.
Solutions
- Remove the post-aggregator from the ORDER BY / limit spec, sorting only by dimensions or aggregators
- Convert the post-aggregator expression into an actual aggregator where possible
- Disable limit push down (applyLimitPushDown=false) so the limit is applied after post-aggregation
Example fix
// before
.limit(new DefaultLimitSpec(ImmutableList.of(new OrderByColumnSpec("ratio", ASC)), 10)) // 'ratio' is a post-agg
// after
.limit(new DefaultLimitSpec(ImmutableList.of(new OrderByColumnSpec("count", ASC)), 10)) // sort by aggregator Defensive patterns
Strategy: validation
Validate before calling
boolean sortsByPostAgg = ((DefaultLimitSpec) q.getLimitSpec()).getColumns().stream().anyMatch(c -> OrderByColumnSpec.getPostAggIndexForOrderBy(c, q.getPostAggregatorSpecs()) > -1);
Type guard
boolean limitColumnsAreNotPostAggs(GroupByQuery q) { return q.getLimitSpec() instanceof DefaultLimitSpec && ((DefaultLimitSpec) q.getLimitSpec()).getColumns().stream().noneMatch(c -> OrderByColumnSpec.getPostAggIndexForOrderBy(c, q.getPostAggregatorSpecs()) > -1); } Try / catch
try { validateAndGetForceLimitPushDown(query, forcePushDown); } catch (UnsupportedOperationException e) { return false; } Prevention
- Only order by dimension or aggregator output names when using limit push down
- Keep post-aggregators out of ORDER BY clauses in push-down-enabled queries
When it happens
Trigger: Calling GroupByQuery.isApplyLimitPushDown / validateAndGetForceLimitPushDown with a DefaultLimitSpec whose OrderByColumnSpec matches (via getPostAggIndexForOrderBy) one of the query's postAggregatorSpecs while forcing push down.
Common situations: SQL ORDER BY on an expression computed from aggregations translated into a post-aggregator sort with limit push down enabled; hand-built native queries sorting on ratio/computed columns with limits.
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
- Comparing arrays of estimates and error bounds is not…
- Comparing arrays of quantiles is not supported
- Comparing arrays of quantiles is not supported
- Comparing histograms is not supported
- Comparing histograms is not supported
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/373626f173a0899a.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/groupby/GroupByQuery.java:519
private boolean validateAndGetForceLimitPushDown()
{
final boolean forcePushDown = context().getBoolean(GroupByQueryConfig.CTX_KEY_FORCE_LIMIT_PUSH_DOWN, false);
if (forcePushDown) {
if (!(limitSpec instanceof DefaultLimitSpec)) {
throw new IAE("When forcing limit push down, a limit spec must be provided.");
}
if (!((DefaultLimitSpec) limitSpec).isLimited()) {
throw new IAE("When forcing limit push down, the provided limit spec must have a limit.");
}
if (havingSpec != null) {
throw new IAE("Cannot force limit push down when a having spec is present.");
}
for (OrderByColumnSpec orderBySpec : ((DefaultLimitSpec) limitSpec).getColumns()) {
if (OrderByColumnSpec.getPostAggIndexForOrderBy(orderBySpec, postAggregatorSpecs) > -1) {
throw new UnsupportedOperationException("Limit push down when sorting by a post aggregator is not supported.");
}
}
}
return forcePushDown;
}
private RowSignature computeResultRowSignature(final RowSignature.Finalization finalization)
{
final RowSignature.Builder builder = RowSignature.builder();
if (universalTimestamp == null) {
builder.addTimeColumn();
}
return builder.addDimensions(dimensions)
.addAggregators(aggregatorSpecs, finalization)
.addPostAggregators(postAggregatorSpecs)
.build();View on GitHub (pinned to 9b90983fd2)