prestodb/presto · error · PrestoException

GENERIC_INTERNAL_ERROR

GENERIC_INTERNAL_ERROR

Error message

Cannot assign canonical plan id to Canonical join node: %s

What it means

CanonicalPlanNode wrappers track an optional stats-equivalent plan node id. For a CanonicalJoinNode this assignment is deliberately unsupported: canonical join nodes are structural stand-ins that must never be the target of stats-equivalence mapping. Hitting this throw means the canonical planner attempted to attach a stats-equivalent id to the join wrapper itself — an internal invariant violation.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalJoinNode.java:104

    @Override
    @JsonProperty
    public List<VariableReferenceExpression> getOutputVariables()
    {
        return outputVariables;
    }

    @Override
    @JsonProperty
    public PlanNode replaceChildren(List<PlanNode> newChildren)
    {
        return new CanonicalJoinNode(getId(), newChildren, type, criteria, filters, outputVariables);
    }

    @Override
    @JsonProperty
    public PlanNode assignStatsEquivalentPlanNode(Optional<PlanNode> statsEquivalentPlanNode)
    {
        throw new PrestoException(GENERIC_INTERNAL_ERROR, format("Cannot assign canonical plan id to Canonical join node: %s", this));
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        CanonicalJoinNode that = (CanonicalJoinNode) o;
        return Objects.equals(sources, that.sources) &&
                Objects.equals(type, that.type) &&
                Objects.equals(criteria, that.criteria) &&
                Objects.equals(filters, that.filters) &&
                Objects.equals(outputVariables, that.outputVariables);
    }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Report this to the Presto maintainers with the query plan and stack trace — it indicates an internal invariant violation
  2. Upgrade to a newer Presto version where canonical plan handling may be fixed
  3. If in custom code, ensure stats-equivalent assignment targets the underlying plan node, not the CanonicalJoinNode wrapper

Example fix

// before (custom rule)
context.recordStatsEquivalent(canonicalJoinNode);
// after
context.recordStatsEquivalent(canonicalJoinNode.getStatsEquivalentPlanNode().orElse(canonicalJoinNode.getSource()));
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard before assignment
if (node instanceof CanonicalJoinNode) {
    throw new IllegalStateException("Stats-equivalent id must target the underlying join, not the canonical wrapper");
}

Type guard

boolean isCanonicalWrapper(PlanNode n) {
    return n instanceof CanonicalJoinNode || n instanceof CanonicalTableScanNode;
}

Try / catch

try { canonicalPlanner.plan(...); } catch (PrestoException e) { if (e.getErrorCode().equals(GENERIC_INTERNAL_ERROR.toErrorCode()) && e.getMessage().contains("Cannot assign canonical plan id")) { reportInternalBug(e); } else throw e; }

Prevention

When it happens

Trigger: Internal planner path where assignStatsEquivalentPlanNode is invoked on a CanonicalJoinNode during canonical plan generation/serialization in rule-based optimization or stats collection.

Common situations: Engine bugs after upgrading Presto; custom plan optimizers or listeners that walk canonical plans and call assignment APIs; novel plan shapes that route stats-equivalence bookkeeping to the wrong node.

Related errors


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