prestodb/presto · error · PrestoException
GENERIC_INTERNAL_ERROR
GENERIC_INTERNAL_ERROR
Error message
Unexpected call replaceChildren for %s
What it means
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.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/planner/StatsEquivalentPlanNodeWithLimit.java:94
}
@JsonProperty
public PlanNode getLimit()
{
return limit;
}
@Override
public List<VariableReferenceExpression> getOutputVariables()
{
return plan.getOutputVariables();
}
@Override
@JsonProperty
public PlanNode replaceChildren(List<PlanNode> newChildren)
{
throw new PrestoException(GENERIC_INTERNAL_ERROR, format("Unexpected call replaceChildren for %s", this));
}
@Override
@JsonProperty
public PlanNode assignStatsEquivalentPlanNode(Optional<PlanNode> statsEquivalentPlanNode)
{
throw new PrestoException(GENERIC_INTERNAL_ERROR, format("Cannot assign canonical plan id for: %s", this));
}
@Override
public <R, C> R accept(InternalPlanVisitor<R, C> visitor, C context)
{
return visitor.visitStatsEquivalentPlanNodeWithLimit(this, context);
}
@Override
public boolean equals(Object o)
{View on GitHub (pinned to 55bb57d202)
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
Defensive patterns
Strategy: try-catch
Type guard
boolean isStatsEquivalentWrapper(PlanNode node) {
return node instanceof StatsEquivalentPlanNodeWithLimit;
} Try / catch
try {
optimizer.apply(rules, plan);
} catch (PrestoException e) {
if (e.getErrorCode().getName().equals("GENERIC_INTERNAL_ERROR") && e.getMessage().contains("replaceChildren")) {
throw new IllegalStateException("Optimizer rule rewrote StatsEquivalentPlanNodeWithLimit; report bug", e);
}
throw e;
} Prevention
- 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
When it happens
Trigger: An optimizer rule (e.g. a PlanRewriter or node-replace pass) invokes replaceChildren on a StatsEquivalentPlanNodeWithLimit instance during plan optimization.
Common situations: 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.
Related errors
- GENERIC_INTERNAL_ERROR
- CLICKHOUSE_QUERY_GENERATOR_FAILURE
- GENERIC_INTERNAL_ERROR
- GENERIC_INTERNAL_ERROR
- GENERIC_INTERNAL_ERROR
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/0a22747c6fdfff92.
Report an issue: GitHub.