{"record":{"id":"8f5b675eba335c63","repo":"apache/beam","slug":"unexpected-rexnode-encountered-classname","errorCode":null,"errorMessage":"Unexpected RexNode encountered: ${className}","messagePattern":"Unexpected RexNode encountered: (.+?)","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rule/BeamIOPushDownRule.java","lineNumber":210,"sourceCode":"    while (!prerequisites.isEmpty()) {\n      RexNode node = prerequisites.poll();\n\n      if (node instanceof RexCall) { // Composite expression, example: \"=($t11, $t12)\"\n        RexCall compositeNode = (RexCall) node;\n\n        // Expression from example above contains 2 operands: $t11, $t12\n        prerequisites.addAll(compositeNode.getOperands());\n      } else if (node instanceof RexInputRef) { // Input reference\n        // Find a field in an inputRowType for the input reference\n        int inputFieldIndex = ((RexInputRef) node).getIndex();\n        RelDataTypeField field = inputRowType.getFieldList().get(inputFieldIndex);\n\n        // If we have not seen it before - add it to the list (hash set)\n        usedFields.add(field.getName());\n      } else if (node instanceof RexLiteral) {\n        // Does not contain information about columns utilized by a Calc\n      } else {\n        throw new UnsupportedOperationException(\n            \"Unexpected RexNode encountered: \" + node.getClass().getSimpleName());\n      }\n    }\n  }\n\n  /**\n   * Recursively reconstruct a {@code RexNode}, mapping old RexInputRefs to new.\n   *\n   * @param node {@code RexNode} to reconstruct.\n   * @param inputRefMapping Mapping from old {@code RexInputRefNode} indexes to new, where list\n   *     index is the new {@code RexInputRefNode} and the value is old {@code RexInputRefNode}.\n   * @return reconstructed {@code RexNode} with {@code RexInputRefNode} remapped to new values.\n   */\n  @VisibleForTesting\n  RexNode reMapRexNodeToNewInputs(RexNode node, List<Integer> inputRefMapping) {\n    if (node instanceof RexInputRef) {\n      int oldInputIndex = ((RexInputRef) node).getIndex();\n      int newInputIndex = inputRefMapping.indexOf(oldInputIndex);","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/rule/BeamIOPushDownRule.java#L192-L228","documentation":"During I/O push-down optimization, BeamIOPushDownRule walks the RexNode expressions of a Calc to determine which input fields are used. Only RexInputRef (column refs) and RexLiteral are handled; any other RexNode subclass triggers an UnsupportedOperationException.","triggerScenarios":"A Calc node whose condition/expression list contains an unhandled RexNode type (e.g. RexCall composed in an unexpected way, RexFieldAccess) while the push-down rule calls findUtilizedInputRefs via onMatch.","commonSituations":"Complex SQL projections or filters (CASE expressions, nested function calls, subquery-derived refs) hitting the optimizer; often surfaces after Calcite upgrades change RexNode shape.","solutions":["Simplify the SQL expression so it uses only plain column references and literals","Restructure the query to move complex expressions out of the pushed-down Calc","Upgrade Beam, which may add handling for more RexNode types"],"exampleFix":"// before\nSELECT CASE WHEN f1 > 0 THEN f1 ELSE -f1 END FROM t\n// after\nSELECT f1 FROM t -- compute the CASE expression after IO push-down, outside the optimized Calc","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean isSupportedRexNode(RexNode n) { return n instanceof RexInputRef || n instanceof RexLiteral; }","tryCatchPattern":"try { plan = optimizer.transform(...) } catch (UnsupportedOperationException e) { plan = unoptimizedPlan; }","preventionTips":["Keep pushed-down projections to simple column refs and literals","Test queries with complex CASE/function expressions against the Beam version","Handle the exception by falling back to the unoptimized plan"],"tags":["sql","calcite","unsupported-operation"],"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"}