{"record":{"id":"edc8af090c457165","repo":"prestodb/presto","slug":"generic-internal-error-edc8af","errorCode":"GENERIC_INTERNAL_ERROR","errorMessage":"Cannot assign canonical plan id to Canonical join node: %s","messagePattern":"Cannot assign canonical plan id to Canonical join node: (.+?)","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalJoinNode.java","lineNumber":104,"sourceCode":"    @Override\n    @JsonProperty\n    public List<VariableReferenceExpression> getOutputVariables()\n    {\n        return outputVariables;\n    }\n\n    @Override\n    @JsonProperty\n    public PlanNode replaceChildren(List<PlanNode> newChildren)\n    {\n        return new CanonicalJoinNode(getId(), newChildren, type, criteria, filters, outputVariables);\n    }\n\n    @Override\n    @JsonProperty\n    public PlanNode assignStatsEquivalentPlanNode(Optional<PlanNode> statsEquivalentPlanNode)\n    {\n        throw new PrestoException(GENERIC_INTERNAL_ERROR, format(\"Cannot assign canonical plan id to Canonical join node: %s\", this));\n    }\n\n    @Override\n    public boolean equals(Object o)\n    {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n        CanonicalJoinNode that = (CanonicalJoinNode) o;\n        return Objects.equals(sources, that.sources) &&\n                Objects.equals(type, that.type) &&\n                Objects.equals(criteria, that.criteria) &&\n                Objects.equals(filters, that.filters) &&\n                Objects.equals(outputVariables, that.outputVariables);\n    }","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/planner/CanonicalJoinNode.java#L86-L122","documentation":"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.","triggerScenarios":"Internal planner path where assignStatsEquivalentPlanNode is invoked on a CanonicalJoinNode during canonical plan generation/serialization in rule-based optimization or stats collection.","commonSituations":"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.","solutions":["Report this to the Presto maintainers with the query plan and stack trace — it indicates an internal invariant violation","Upgrade to a newer Presto version where canonical plan handling may be fixed","If in custom code, ensure stats-equivalent assignment targets the underlying plan node, not the CanonicalJoinNode wrapper"],"exampleFix":"// before (custom rule)\ncontext.recordStatsEquivalent(canonicalJoinNode);\n// after\ncontext.recordStatsEquivalent(canonicalJoinNode.getStatsEquivalentPlanNode().orElse(canonicalJoinNode.getSource()));","handlingStrategy":"try-catch","validationCode":"// Guard before assignment\nif (node instanceof CanonicalJoinNode) {\n    throw new IllegalStateException(\"Stats-equivalent id must target the underlying join, not the canonical wrapper\");\n}","typeGuard":"boolean isCanonicalWrapper(PlanNode n) {\n    return n instanceof CanonicalJoinNode || n instanceof CanonicalTableScanNode;\n}","tryCatchPattern":"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; }","preventionTips":["Never call assignStatsEquivalentPlanNode on canonical wrapper nodes","Target the wrapped source node for stats bookkeeping","Report occurrences with stack traces — this is an engine invariant violation"],"tags":["planner","internal-error","canonical-plan"],"backgroundTag":"presto-internal-invariant-violation","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}