prestodb/presto · error · PrestoException

GENERIC_INTERNAL_ERROR

GENERIC_INTERNAL_ERROR

Error message

Unexpected plan node between partial and final aggregation

What it means

MergePartialAggregationsWithFilter rewrites plans where a partial aggregation is directly chained to its final aggregation so the filter can be merged. Its default visitPlan asserts no other node type appears between the partial and final aggregation; if the context still holds entries after rewriting all children, the optimizer found an unexpected plan node between them, indicating a broken planner invariant rather than a user mistake.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MergePartialAggregationsWithFilter.java:201

        public static RowExpression ifThenElse(RowExpression... arguments)
        {
            return specialForm(SpecialFormExpression.Form.IF, arguments[1].getType(), arguments);
        }

        public boolean isPlanChanged()
        {
            return planChanged;
        }

        @Override
        public PlanNode visitPlan(PlanNode node, RewriteContext<Context> context)
        {
            List<PlanNode> children = node.getSources().stream()
                    .map(child -> context.rewrite(child, context.get()))
                    .collect(toImmutableList());
            if (!context.get().isEmpty()) {
                throw new PrestoException(GENERIC_INTERNAL_ERROR, "Unexpected plan node between partial and final aggregation");
            }
            return replaceChildren(node, children);
        }

        @Override
        public PlanNode visitAggregation(AggregationNode node, RewriteContext<Context> context)
        {
            PlanNode rewrittenSource = context.rewrite(node.getSource(), context.get());
            // Before optimization, for aggregations with filter, input rows will be skipped if mask is false. However, after optimization, the partial
            // aggregation output is projected to be NULL if mask is false. We need to have the function to not calledOnNullInput to ensure correctness.
            // Applying optimizations on global aggregations will lead to exception at
            // https://github.com/prestodb/presto/blob/dfbf21744ccd900d1a650571ffc35915db9b9f59/presto-main/src/main/java/com/facebook/presto/operator/HashAggregationOperator.java#L627
            boolean canOptimize = !node.getGroupingKeys().isEmpty() && node.getAggregations().values().stream()
                    .map(x -> functionAndTypeManager.getFunctionMetadata(x.getFunctionHandle())).noneMatch(x -> x.isCalledOnNullInput());
            if (canOptimize) {
                checkState(node.getAggregations().values().stream().noneMatch(x -> x.getFilter().isPresent()), "All aggregation filters should already be rewritten to mask before this optimization");
                if (node.getStep().equals(PARTIAL)) {
                    planChanged = true;

View on GitHub (pinned to 55bb57d202)

Solutions

  1. File a bug with the full query text and EXPLAIN (the failing SQL) so the planner team can extend the rewriter.
  2. Try restructuring the query (simplify the aggregation/filter composition, add explicit subqueries) to sidestep the pattern.
  3. Bisect or downgrade if the failure appeared after a Presto upgrade, and check release notes for related optimizer fixes.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    execute(sql);
} catch (PrestoException e) {
    if ("GENERIC_INTERNAL_ERROR".equals(e.getErrorCode().getName()) && e.getMessage().contains("Unexpected plan node between partial and final aggregation")) {
        // restructure query or report bug; retrying will not help
        reportBug(sql, e);
    } else throw e;
}

Prevention

When it happens

Trigger: A plan in which the optimizer's pattern matching identified a partial/final aggregation pair, but when rewriting descendants an intermediate node type (not handled by the specialized visitors) appears between partial and final aggregation — a planner bug or a rule-interaction edge case in query plan shape.

Common situations: Complex queries combining aggregations with filters, joins, or other optimization passes that interleave nodes between partial and final aggregation; usually surfaces after upgrading or with unusual query constructs; it is an internal invariant violation, not caused by user SQL semantics alone.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/91f806c89afa3f39. Report an issue: GitHub.