{"record":{"id":"0f7d78342bb38e0a","repo":"apache/beam","slug":"predicate-node-s-should-be-a-boolean-expression-but-was-s","errorCode":null,"errorMessage":"Predicate node '%s' should be a boolean expression, but was: %s","messagePattern":"Predicate node '(.+?)' should be a boolean expression, but was: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/bigquery/BigQueryFilter.java","lineNumber":64,"sourceCode":"  \"nullness\" // TODO(https://github.com/apache/beam/issues/20497)\n})\npublic class BigQueryFilter implements BeamSqlTableFilter {\n  private static final ImmutableSet<SqlKind> SUPPORTED_OPS =\n      ImmutableSet.<SqlKind>builder()\n          .add(COMPARISON.toArray(new SqlKind[0]))\n          // TODO: Check what other functions are supported and add support for them (ex: trim).\n          .add(PLUS, MINUS, MOD, DIVIDE, TIMES, LIKE, BETWEEN, CAST, AND, OR)\n          .build();\n  private List<RexNode> supported;\n  private List<RexNode> unsupported;\n\n  public BigQueryFilter(List<RexNode> predicateCNF) {\n    supported = new ArrayList<>();\n    unsupported = new ArrayList<>();\n\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        supported.add(node);\n      } else {\n        unsupported.add(node);\n      }\n    }\n  }\n\n  @Override\n  public List<RexNode> getNotSupported() {\n    return unsupported;\n  }","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/bigquery/BigQueryFilter.java#L46-L82","documentation":"The BigQueryFilter constructor validates that every predicate in the CNF (conjunctive normal form) list is a boolean-typed expression. If any RexNode's type is not SqlTypeName.BOOLEAN — meaning a non-boolean expression was handed to the pushdown filter builder — it throws IllegalArgumentException identifying the node and its actual SQL type.","triggerScenarios":"Constructing BigQueryFilter with a List<RexNode> predicateCNF that includes a non-boolean node, e.g. a literal, arithmetic result, or column reference of type INTEGER/VARCHAR instead of a comparison.","commonSituations":"Building filter pushdown pipelines where CNF extraction accidentally includes projected (non-filter) expressions; custom rel nodes passing raw operands rather than boolean conjunctions; optimizer rewrites changing node types.","solutions":["Pass only boolean predicates (comparisons, AND/OR of comparisons) into BigQueryFilter","Filter the CNF list to nodes whose getType().getSqlTypeName() == SqlTypeName.BOOLEAN before constructing","Check how predicates are extracted (RexUtil/condition splitting) to avoid pulling non-condition expressions into the CNF"],"exampleFix":"// before\nnew BigQueryFilter(allProjectExpressions)\n// after\nList<RexNode> booleanPreds = allProjectExpressions.stream()\n    .filter(n -> n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN))\n    .collect(Collectors.toList());\nnew BigQueryFilter(booleanPreds)","handlingStrategy":"validation","validationCode":"// before constructing\nboolean allBoolean = predicateCNF.stream()\n    .allMatch(n -> n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN));\nif (!allBoolean) throw new IllegalArgumentException(\"CNF list must contain only boolean predicates\");","typeGuard":"boolean isBooleanPredicate(RexNode n) {\n  return n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN);\n}","tryCatchPattern":"try {\n  BigQueryFilter f = new BigQueryFilter(cnf);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"should be a boolean expression\")) { /* sanitize inputs and retry */ }\n  throw e;\n}","preventionTips":["Extract only condition expressions (RexUtil conjunctions) for pushdown","Filter CNF inputs to boolean-typed nodes before constructing BigQueryFilter","Assert node types in tests for your custom rel rules"],"tags":["beam-sql","bigquery","predicate-pushdown","type-mismatch"],"backgroundTag":"type-mismatch","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"}