prestodb/presto · error · PrestoException
GENERIC_INTERNAL_ERROR
GENERIC_INTERNAL_ERROR
Error message
Expect exactly 1 child PlanNode
What it means
TopNNode validates its plan structure invariants during construction and child replacement via checkCondition. When a TopNNode is built or rewritten with a number of children other than exactly one (a TopN operator always consumes a single input plan), the SPI throws GENERIC_INTERNAL_ERROR. This signals a broken optimizer rule or connector-provided plan, not a user query problem per se.
Source
Thrown at presto-spi/src/main/java/com/facebook/presto/spi/plan/TopNNode.java:162
@Override
public PlanNode replaceChildren(List<PlanNode> newChildren)
{
checkCondition(newChildren != null && newChildren.size() == 1, GENERIC_INTERNAL_ERROR, "Expect exactly 1 child PlanNode");
return new TopNNode(getSourceLocation(), getId(), getStatsEquivalentPlanNode(), newChildren.get(0), count, orderingScheme, step);
}
private static void checkArgument(boolean condition, String message)
{
if (!condition) {
throw new IllegalArgumentException(message);
}
}
private static void checkCondition(boolean condition, ErrorCodeSupplier errorCode, String formatString, Object... args)
{
if (!condition) {
throw new PrestoException(errorCode, format(formatString, args));
}
}
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Inspect the optimizer/rewriter rule that produced the TopNNode and ensure replaceChildren is called with exactly one child
- Verify the query works without the custom plugin/rule to isolate the faulty component
- Check for version mismatches between presto-spi and custom plugins and rebuild against the matching SPI
- If reproducible in stock Presto, file a bug with the query and EXPLAIN (VERBOSE) output
Example fix
// before node.replaceChildren(rewrittenChildren); // after com.google.common.collect.ImmutableList<PlanNode> children = rewrittenChildren.stream().limit(1).collect(ImmutableList.toImmutableList()); node.replaceChildren(children); // TopNNode requires exactly one child
Defensive patterns
Strategy: validation
Validate before calling
if (children == null || children.size() != 1) {
throw new IllegalStateException("TopNNode requires exactly 1 child, got " + (children == null ? "null" : children.size()));
} Type guard
static boolean hasSingleChild(PlanNode node) {
return node.getSources().size() == 1;
} Try / catch
try {
planRewriter.rewrite(topnNode);
} catch (PrestoException e) {
if (e.getErrorCode().getCode() == StandardErrorCode.GENERIC_INTERNAL_ERROR.toErrorCode().getCode()) {
LOG.error("Plan rewrite produced invalid TopNNode arity", e);
}
throw e;
} Prevention
- Always build TopNNode with a single source child; assert list size in custom rewriters
- Add unit tests for custom optimizer rules covering TopNNode replaceChildren
- Keep plugins compiled against the same presto-spi version as the server
When it happens
Trigger: Calling TopNNode constructor or replaceChildren(...) with a child list of size 0 or >= 2, e.g. a custom optimizer/PlanRewriter that removes the source child or wraps TopN in multiple inputs.
Common situations: Custom PlanRewriter/Optimizer rules that mis-handle TopNNode; connector or engine version mismatch where a rule produces an unexpected plan shape; bugs in plan serialization/deserialization round-trips.
Related errors
- CLICKHOUSE_QUERY_GENERATOR_FAILURE
- GENERIC_INTERNAL_ERROR
- GENERIC_INTERNAL_ERROR
- GENERIC_INTERNAL_ERROR
- GENERIC_INTERNAL_ERROR
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/4dd383c3587adfa2.
Report an issue: GitHub.