prestodb/presto · error · PrestoException
DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
Error message
Druid does not support filter on top of AggregationNode.
What it means
Druid's native groupBy/topN query model does not allow an outer filter applied above the aggregation result the way Presto plans it (filter on top of AggregationNode). The context builder refuses to attach a filter once aggregations exist, since it cannot express the plan faithfully in a single Druid query.
Source
Thrown at presto-druid/src/main/java/com/facebook/presto/druid/DruidQueryGeneratorContext.java:115
Set<VariableReferenceExpression> variablesInAggregation,
Set<VariableReferenceExpression> hiddenColumnSet,
Optional<PlanNodeId> tableScanNodeId)
{
this.selections = new LinkedHashMap<>(requireNonNull(selections, "selections can't be null"));
this.from = requireNonNull(from, "source can't be null");
this.filter = requireNonNull(filter, "filter is null");
this.limit = requireNonNull(limit, "limit is null");
this.aggregations = aggregations;
this.groupByColumns = new LinkedHashMap<>(requireNonNull(groupByColumns, "groupByColumns can't be null. It could be empty if not available"));
this.hiddenColumnSet = requireNonNull(hiddenColumnSet, "hidden column set is null");
this.variablesInAggregation = requireNonNull(variablesInAggregation, "variables in aggregation is null");
this.tableScanNodeId = requireNonNull(tableScanNodeId, "tableScanNodeId can't be null");
}
public DruidQueryGeneratorContext withFilter(String filter)
{
if (hasAggregation()) {
throw new PrestoException(DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION, "Druid does not support filter on top of AggregationNode.");
}
checkState(!hasFilter(), "Druid doesn't support filters at multiple levels under AggregationNode");
return new DruidQueryGeneratorContext(
selections,
from,
Optional.of(filter),
limit,
aggregations,
groupByColumns,
variablesInAggregation,
hiddenColumnSet,
tableScanNodeId);
}
public DruidQueryGeneratorContext withProject(Map<VariableReferenceExpression, Selection> newSelections)
{
return new DruidQueryGeneratorContext(
newSelections,View on GitHub (pinned to 55bb57d202)
Solutions
- Rewrite as a HAVING clause (SELECT k, sum(v) FROM t GROUP BY k HAVING sum(v) > 10) so the filter folds into the aggregation
- Disable pushdown (connector-level or session property) so the filter is evaluated in Presto
- Restructure the query to filter base columns before aggregation (push filters below the GROUP BY)
- Modify DruidQueryGeneratorContext/visitor to convert qualifying post-aggregation filters into Druid having specs
Example fix
// before SELECT * FROM (SELECT k, sum(v) s FROM t GROUP BY k) WHERE s > 10; -- throws // after SELECT k, sum(v) FROM t GROUP BY k HAVING sum(v) > 10;
Defensive patterns
Strategy: try-catch
Validate before calling
boolean isFilterAboveAggregationSafe(PlanNode filterNode) {
return !(filterNode.getSource() instanceof AggregationNode);
} Try / catch
try { return context.withFilter(filterSql); }
catch (PrestoException e) {
if (DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION.getCode().equals(e.getErrorCode().getCode())) {
return skipPushdownAndEvaluateFilterInPresto();
}
throw e;
} Prevention
- Express post-aggregation conditions as HAVING, not as outer WHERE on derived tables
- Filter raw columns before GROUP BY, not aggregate results after
- Avoid chaining aggregation under aggregation or filter-over-subquery patterns on Druid tables
- Test plan pushdown with EXPLAIN before deploying report queries
When it happens
Trigger: A query plan reaches visitFilter after aggregation was recorded, e.g. SELECT ... FROM (SELECT k, sum(v) AS s FROM t GROUP BY k) WHERE s > 10 — a HAVING-like/outer filter over an aggregate — and the connector tries to push the filter into the Druid context.
Common situations: Filtering on the result of an aggregate (HAVING with complex expressions) or filtering a derived table built on top of a Druid aggregation; typically surfaces when the planner attempts predicate pushdown past an AggregationNode.
Related errors
- DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
- CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION
- DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
- CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION
- DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/c2faeb85adcd0540.
Report an issue: GitHub.