{"record":{"id":"5681dd1c26000c62","repo":"apache/beam","slug":"cannot-get-limit-count-from-relnode-tree-with-root","errorCode":null,"errorMessage":"Cannot get limit count from RelNode tree with root ${relTypeName}","messagePattern":"Cannot get limit count from RelNode tree with root (.+?)","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamEnumerableConverter.java","lineNumber":428,"sourceCode":"    public void processElement(@SuppressWarnings(\"unused\") ProcessContext context) {\n      rows.inc();\n    }\n  }\n\n  private static boolean isLimitQuery(BeamRelNode node) {\n    return (node instanceof BeamSortRel && ((BeamSortRel) node).isLimitOnly())\n        || (node instanceof AbstractBeamCalcRel\n            && ((AbstractBeamCalcRel) node).isInputSortRelAndLimitOnly());\n  }\n\n  private static int getLimitCount(BeamRelNode node) {\n    if (node instanceof BeamSortRel) {\n      return ((BeamSortRel) node).getCount();\n    } else if (node instanceof AbstractBeamCalcRel) {\n      return ((AbstractBeamCalcRel) node).getLimitCountOfSortRel();\n    }\n\n    throw new IllegalArgumentException(\n        \"Cannot get limit count from RelNode tree with root \" + node.getRelTypeName());\n  }\n\n  private static boolean containsUnboundedPCollection(Pipeline p) {\n    class BoundednessVisitor extends PipelineVisitor.Defaults {\n      IsBounded boundedness = IsBounded.BOUNDED;\n\n      @Override\n      public void visitValue(PValue value, Node producer) {\n        if (value instanceof PCollection) {\n          boundedness = boundedness.and(((PCollection) value).isBounded());\n        }\n      }\n    }\n\n    BoundednessVisitor visitor = new BoundednessVisitor();\n    p.traverseTopologically(visitor);\n    return visitor.boundedness == IsBounded.UNBOUNDED;","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rel/BeamEnumerableConverter.java#L410-L446","documentation":"During SQL LIMIT planning, BeamEnumerableConverter walks the RelNode tree to extract the row-count limit. It recognizes only BeamSortRel (direct LIMIT) and AbstractBeamCalcRel (LIMIT under a calc); any other root shape makes planning fail with this IllegalArgumentException.","triggerScenarios":"Running a Beam SQL query with LIMIT whose top node above the sort is neither BeamSortRel nor AbstractBeamCalcRel, e.g. LIMIT combined with operators not yet handled by getLimitCount.","commonSituations":"Queries like SELECT ... LIMIT n wrapped by other relational operators (aggregates, sets, joins) so the converter sees an unsupported RelNode root; usually surfaced when enabling an enumerable-converter-based execution path.","solutions":["Rewrite the query so LIMIT appears in a shape the converter supports (a plain sort/limit or a calc directly over it)","Check the Beam version; newer releases extend getLimitCount to more RelNode types, so upgrade","If extending Beam, add a branch in getLimitCount for your RelNode type exposing its count"],"exampleFix":"// before\nthrow new IllegalArgumentException(\"Cannot get limit count from RelNode tree with root \" + node.getRelTypeName());\n// after\nif (node instanceof BeamSetOperatorRelBase) {\n  return ((BeamSetOperatorRelBase) node).getLimitCount(); // handle the new node type\n}\nthrow new IllegalArgumentException(\"Cannot get limit count from RelNode tree with root \" + node.getRelTypeName());","handlingStrategy":"try-catch","validationCode":"// Verify the limit-bearing node type before triggering conversion\nboolean limitSupported = root instanceof BeamSortRel || root instanceof AbstractBeamCalcRel;\nif (!limitSupported) throw new IllegalStateException(\"LIMIT shape unsupported: \" + root.getRelTypeName());","typeGuard":"boolean hasExtractableLimit(BeamRelNode node) {\n  return node instanceof BeamSortRel || node instanceof AbstractBeamCalcRel;\n}","tryCatchPattern":"try {\n  sqlEnv.sqlQuery(query).evaluate();\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Cannot get limit count from RelNode tree\")) {\n    // fall back to a query without the unsupported LIMIT wrapper or rewrite it\n  } else throw e;\n}","preventionTips":["Keep LIMIT directly on top of a sort or simple projection","Test LIMIT queries against all shapes used in production","Pin Beam versions so planner node shapes are known"],"tags":["sql","planning","limit","beam"],"backgroundTag":"unsupported-operation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}