{"record":{"id":"0a22747c6fdfff92","repo":"prestodb/presto","slug":"generic-internal-error-0a2274","errorCode":"GENERIC_INTERNAL_ERROR","errorMessage":"Unexpected call replaceChildren for %s","messagePattern":"Unexpected call replaceChildren for (.+?)","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/sql/planner/StatsEquivalentPlanNodeWithLimit.java","lineNumber":94,"sourceCode":"    }\n\n    @JsonProperty\n    public PlanNode getLimit()\n    {\n        return limit;\n    }\n\n    @Override\n    public List<VariableReferenceExpression> getOutputVariables()\n    {\n        return plan.getOutputVariables();\n    }\n\n    @Override\n    @JsonProperty\n    public PlanNode replaceChildren(List<PlanNode> newChildren)\n    {\n        throw new PrestoException(GENERIC_INTERNAL_ERROR, format(\"Unexpected call replaceChildren for %s\", this));\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 for: %s\", this));\n    }\n\n    @Override\n    public <R, C> R accept(InternalPlanVisitor<R, C> visitor, C context)\n    {\n        return visitor.visitStatsEquivalentPlanNodeWithLimit(this, context);\n    }\n\n    @Override\n    public boolean equals(Object o)\n    {","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/sql/planner/StatsEquivalentPlanNodeWithLimit.java#L76-L112","documentation":"StatsEquivalentPlanNodeWithLimit is a plan-node wrapper used for statistics equivalence tracking that intentionally does not support structural rewrites. Its replaceChildren override unconditionally throws GENERIC_INTERNAL_ERROR, so calling it means the optimizer tried to modify children of a node that must remain immutable — an engine-internal invariant violation.","triggerScenarios":"An optimizer rule (e.g. a PlanRewriter or node-replace pass) invokes replaceChildren on a StatsEquivalentPlanNodeWithLimit instance during plan optimization.","commonSituations":"A Presto engine bug where a plan optimizer rule does not skip stats-equivalence wrapper nodes; custom optimizer rules/plugins that traverse and rewrite all plan nodes without special-casing this type.","solutions":["This indicates an internal error — file a bug with the query and full stack trace to the Presto project","Identify the optimizer rule in the stack trace that rewrote the node and exclude/bypass it","Upgrade Presto to a version where the rewriting rule handles StatsEquivalentPlanNodeWithLimit correctly","If you wrote a custom rule/visitor, skip or specially handle StatsEquivalentPlanNodeWithLimit nodes"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"boolean isStatsEquivalentWrapper(PlanNode node) {\n    return node instanceof StatsEquivalentPlanNodeWithLimit;\n}","tryCatchPattern":"try {\n    optimizer.apply(rules, plan);\n} catch (PrestoException e) {\n    if (e.getErrorCode().getName().equals(\"GENERIC_INTERNAL_ERROR\") && e.getMessage().contains(\"replaceChildren\")) {\n        throw new IllegalStateException(\"Optimizer rule rewrote StatsEquivalentPlanNodeWithLimit; report bug\", e);\n    }\n    throw e;\n}","preventionTips":["Exclude StatsEquivalentPlanNodeWithLimit from custom optimizer rewrites","Keep Presto updated; this is usually an engine bug","Never call replaceChildren on stats-equivalence wrapper nodes in plugin code","Attach EXPLAIN plans when reporting such internal errors"],"tags":["presto","planner","internal-error","optimizer"],"backgroundTag":"presto-generic-internal-error","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"}