prestodb/presto · warning · PrestoException
CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION
CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION
Error message
ClickHouse does not support filter on top of AggregationNode.
What it means
The ClickHouse pushdown optimizer only supports pushing a filter below or beside an aggregation (e.g. HAVING-style is not modeled here); it cannot represent a filter applied on top of an AggregationNode in the generated SQL. When withFilter is invoked on a context that already contains an aggregation, the pushdown is aborted so the query falls back to non-pushed execution. This is a deliberate capability limit of the generator, not a ClickHouse server error.
Source
Thrown at presto-clickhouse/src/main/java/com/facebook/presto/plugin/clickhouse/optimization/ClickHouseQueryGeneratorContext.java:120
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.schema = requireNonNull(schema, "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 ClickHouseQueryGeneratorContext withFilter(String filter)
{
if (hasAggregation()) {
throw new PrestoException(CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION, "ClickHouse does not support filter on top of AggregationNode.");
}
checkState(!hasFilter(), "ClickHouse doesn't support filters at multiple levels under AggregationNode");
return new ClickHouseQueryGeneratorContext(
selections,
from,
schema,
Optional.of(filter),
limit,
aggregations,
groupByColumns,
variablesInAggregation,
hiddenColumnSet,
tableScanNodeId);
}
public ClickHouseQueryGeneratorContext withProject(Map<VariableReferenceExpression, Selection> newSelections)
{
return new ClickHouseQueryGeneratorContext(View on GitHub (pinned to 55bb57d202)
Solutions
- Rewrite the query so the filter sits below the aggregation (filter raw rows in a WHERE before grouping) rather than above it.
- Disable ClickHouse pushdown for such queries so Presto executes the filter locally after the aggregation.
- If HAVING is needed, express it in a form the connector supports, or upgrade the connector — check whether your version added HAVING pushdown support.
- File/patch the connector to translate top-of-aggregation filters into HAVING clauses.
Example fix
// before (filter above aggregation) SELECT k, count(*) FROM t GROUP BY k HAVING count(*) > 5; // after (filter below aggregation where possible) SELECT k, count(*) FROM t WHERE valid = true GROUP BY k;
Defensive patterns
Strategy: validation
Validate before calling
// Detect filter-on-top-of-aggregation shape before expecting pushdown
boolean filterAboveAggregation = planContains(FilterNode.class, node ->
childOf(node, AggregationNode.class) && beneathAggregationIsClickHouseScan(node));
// if true, don't rely on pushdown; rewrite or run locally Try / catch
try {
execute(query);
} catch (PrestoException e) {
if ("CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION".equals(e.getErrorCode().getName())) {
executeWithoutPushdown(query); // session-level pushdown disabled fallback
} else {
throw e;
}
} Prevention
- Place row-filtering WHERE clauses below GROUP BY, not above it
- Prefer pushing filters on raw columns; treat HAVING as not pushable for this connector
- Verify plan shapes with EXPLAIN before benchmarking pushdown
- Keep connector updated in case HAVING pushdown is added
When it happens
Trigger: visitFilter calls withFilter(String) while the ClickHouseQueryGeneratorContext already hasAggregation() == true — i.e. the plan has FilterNode -> AggregationNode -> TableScan (or filter otherwise lands above the aggregation during pushdown).
Common situations: Queries like SELECT ... FROM t GROUP BY k HAVING agg ... where the planner builds a filter node on top of the aggregation, or views/subqueries with WHERE clauses wrapped around a GROUP BY, when ClickHouse pushdown is enabled.
Related errors
- CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION
- DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
- CLICKHOUSE_PUSHDOWN_UNSUPPORTED_EXPRESSION
- CLICKHOUSE_QUERY_GENERATOR_FAILURE
- DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/a7861f6e05269e65.
Report an issue: GitHub.