{"record":{"id":"357ed8c992a4b3da","repo":"apache/beam","slug":"predicate-node-nodeclass-should-be-a-boolean-expression-but","errorCode":null,"errorMessage":"Predicate node '${nodeClass}' should be a boolean expression, but was: ${sqlTypeName}","messagePattern":"Predicate node '(.+?)' should be a boolean expression, but was: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/iceberg/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/iceberg/IcebergFilter.java","lineNumber":56,"sourceCode":"\npublic class IcebergFilter implements BeamSqlTableFilter {\n  private @Nullable List<RexNode> supported;\n  private @Nullable List<RexNode> unsupported;\n  private final List<RexNode> predicateCNF;\n\n  public IcebergFilter(List<RexNode> predicateCNF) {\n    this.predicateCNF = predicateCNF;\n  }\n\n  private void maybeInitialize() {\n    if (supported != null && unsupported != null) {\n      return;\n    }\n    ImmutableList.Builder<RexNode> supportedBuilder = ImmutableList.builder();\n    ImmutableList.Builder<RexNode> unsupportedBuilder = ImmutableList.builder();\n    for (RexNode node : predicateCNF) {\n      if (!node.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN)) {\n        throw new IllegalArgumentException(\n            \"Predicate node '\"\n                + node.getClass().getSimpleName()\n                + \"' should be a boolean expression, but was: \"\n                + node.getType().getSqlTypeName());\n      }\n\n      if (isSupported(node).getLeft()) {\n        supportedBuilder.add(node);\n      } else {\n        unsupportedBuilder.add(node);\n      }\n    }\n    supported = supportedBuilder.build();\n    unsupported = unsupportedBuilder.build();\n  }\n\n  @Override\n  public List<RexNode> getNotSupported() {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/iceberg/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/iceberg/IcebergFilter.java#L38-L74","documentation":"IcebergCatalog/SQL predicate pushdown requires every CNF conjunct to be a BOOLEAN-typed RexNode. During filter initialization, if a predicate node's SqlTypeName is not BOOLEAN, Calcite cannot interpret it as a filter condition, so the code throws immediately to prevent generating a wrong filter.","triggerScenarios":"Calling getSupported/numSupported/getNotSupported on an IcebergTable filter where the pushed-down predicate CNF contains a node whose type is not SqlTypeName.BOOLEAN (e.g. an INT comparison result or untyped literal slipped through optimization).","commonSituations":"Custom or malformed predicates passed to Iceberg SQL pushdown, Calcite planner changes that leave non-boolean nodes in the CNF, hand-built RexNode trees in tests or custom table providers.","solutions":["Inspect the predicate SQL and ensure the WHERE clause is a boolean expression (comparisons, AND/OR, IS NULL), not a bare non-boolean value","Re-run optimization/relaxation so predicates are reduced to boolean RexNodes before reaching IcebergFilter","Upgrade/verify the Calcite version matches what Beam SQL expects, since type inference is Calcite's job","If you construct RexNodes programmatically, wrap the expression in a boolean comparison instead of passing a raw value node"],"exampleFix":"// before\nString sql = \"SELECT * FROM tbl WHERE int_col\";\n// after\nString sql = \"SELECT * FROM tbl WHERE int_col > 0\";","handlingStrategy":"validation","validationCode":"if (!node.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN)) {\n  throw new IllegalArgumentException(\"Predicate must be boolean: \" + node);\n}","typeGuard":"boolean isBooleanPredicate(RexNode n) { return n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN); }","tryCatchPattern":null,"preventionTips":["Ensure WHERE clauses evaluate to booleans","Validate predicates before pushdown","Keep Calcite versions aligned with Beam"],"tags":["sql","iceberg","predicate-pushdown","calcite"],"backgroundTag":"invalid-argument-value","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"}