prestodb/presto · error · PinotException

PINOT_UNSUPPORTED_EXPRESSION

PINOT_UNSUPPORTED_EXPRESSION

Error message

Don't know how to handle plan node of type 

What it means

The default branch of the plan visitor (visitPlan) in PinotQueryGenerator throws PINOT_UNSUPPORTED_EXPRESSION 'Don't know how to handle plan node of type <node>' for any PlanNode type it does not explicitly override. The connector only knows how to translate a fixed set of plan nodes (scan, filter, project, aggregate, top-n, etc.); anything else means it cannot generate a Pinot query for that subtree.

Source

Thrown at presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java:232

    class PinotQueryPlanVisitor
            extends PlanVisitor<PinotQueryGeneratorContext, PinotQueryGeneratorContext>
    {
        private final ConnectorSession session;
        private final boolean forbidBrokerQueries;
        private final boolean pushdownTopnBrokerQueries;

        protected PinotQueryPlanVisitor(ConnectorSession session)
        {
            this.session = session;
            this.forbidBrokerQueries = PinotSessionProperties.isForbidBrokerQueries(session);
            this.pushdownTopnBrokerQueries = PinotSessionProperties.getPushdownTopnBrokerQueries(session);
        }

        @Override
        public PinotQueryGeneratorContext visitPlan(PlanNode node, PinotQueryGeneratorContext context)
        {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "Don't know how to handle plan node of type " + node);
        }

        protected VariableReferenceExpression getVariableReference(RowExpression expression)
        {
            if (expression instanceof VariableReferenceExpression) {
                return ((VariableReferenceExpression) expression);
            }
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "Expected a variable reference but got " + expression);
        }

        @Override
        public PinotQueryGeneratorContext visitMarkDistinct(MarkDistinctNode node, PinotQueryGeneratorContext context)
        {
            requireNonNull(context, "context is null");
            return node.getSource().accept(this, context);
        }

        @Override

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Restructure the query so unsupported operations happen above the Pinot subquery: keep pushed-down parts to filters/aggregations/limits on a single table, join or window in an outer query.
  2. Upgrade the Pinot connector plugin to match your Presto engine version so more plan node types are handled.
  3. Check which node type the message names and rewrite that specific operation (e.g. replace a WINDOW with LIMIT/GROUP BY the connector supports).
  4. If the node should be supported, add a visitXxx override in the visitor that translates it or explicitly delegates to Presto execution.

Example fix

// before (join inside the Pinot-subplan triggers the error)
SELECT a.x, b.y FROM pinot_a a JOIN pinot_b b ON a.id = b.id WHERE a.dt = '2026-01-01';

// after (isolate Pinot scans; connector pushes simple filters/aggregations)
WITH s1 AS (SELECT id, x FROM pinot_a WHERE dt = '2026-01-01'),
     s2 AS (SELECT id, y FROM pinot_b)
SELECT s1.x, s2.y FROM s1 JOIN s2 ON s1.id = s2.id;
Defensive patterns

Strategy: fallback

Validate before calling

-- Inspect the plan before execution and check for node types the pinot connector cannot visit:
EXPLAIN ANALYZE? or EXPLAIN <sql>;
-- look for Join/Window/RowNumber/Unnest/Union nodes adjacent to the PinotTableScan;
-- if present, restructure the query

Try / catch

try {
    run(sql);
} catch (PinotException e) {
    if (String.valueOf(e.getMessage()).startsWith("Don't know how to handle plan node")) {
        // retry with the unsupported operation isolated outside the pinot subplan
        run(rewriteToIsolatePinotScan(sql));
    } else throw e;
}

Prevention

When it happens

Trigger: The Presto planner produces a plan node the Pinot connector lacks a visit method for — e.g. JoinNode, WindowNode, RowNumberNode, UnionNode, UnnestNode, MarkDistinctNode (partially supported) or other exotic nodes — directly in the part of the plan the connector attempts to convert.

Common situations: Queries with joins/windows/CTEs/unions over Pinot tables that the planner did not isolate from the Pinot scan; new engine features emitting newer node types the connector predates; version mismatch between Presto core and the Pinot plugin.

Related errors


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