apache/beam · error · IllegalArgumentException
Predicate node ' ' should be a boolean expression, but was
Error message
Predicate node '%s' should be a boolean expression, but was: %s
What it means
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.
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
Example fix
// before
new BigQueryFilter(allProjectExpressions)
// after
List<RexNode> booleanPreds = allProjectExpressions.stream()
.filter(n -> n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN))
.collect(Collectors.toList());
new BigQueryFilter(booleanPreds) Defensive patterns
Strategy: validation
Validate before calling
// before constructing
boolean allBoolean = predicateCNF.stream()
.allMatch(n -> n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN));
if (!allBoolean) throw new IllegalArgumentException("CNF list must contain only boolean predicates"); Type guard
boolean isBooleanPredicate(RexNode n) {
return n.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN);
} Try / catch
try {
BigQueryFilter f = new BigQueryFilter(cnf);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("should be a boolean expression")) { /* sanitize inputs and retry */ }
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Encountered an unexpected node type
- Only INT64 is supported as the interval value for BigQuery.
- Bounded Source is not BigQueryStorageStreamSource, unable…
- Cannot convert BigQuery type '' to '' because the BigQuery…
- Conflicting field types for field
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/0f7d78342bb38e0a.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/meta/provider/bigquery/BigQueryFilter.java:64
"nullness" // TODO(https://github.com/apache/beam/issues/20497)
})
public class BigQueryFilter implements BeamSqlTableFilter {
private static final ImmutableSet<SqlKind> SUPPORTED_OPS =
ImmutableSet.<SqlKind>builder()
.add(COMPARISON.toArray(new SqlKind[0]))
// TODO: Check what other functions are supported and add support for them (ex: trim).
.add(PLUS, MINUS, MOD, DIVIDE, TIMES, LIKE, BETWEEN, CAST, AND, OR)
.build();
private List<RexNode> supported;
private List<RexNode> unsupported;
public BigQueryFilter(List<RexNode> predicateCNF) {
supported = new ArrayList<>();
unsupported = new ArrayList<>();
for (RexNode node : predicateCNF) {
if (!node.getType().getSqlTypeName().equals(SqlTypeName.BOOLEAN)) {
throw new IllegalArgumentException(
"Predicate node '"
+ node.getClass().getSimpleName()
+ "' should be a boolean expression, but was: "
+ node.getType().getSqlTypeName());
}
if (isSupported(node).getLeft()) {
supported.add(node);
} else {
unsupported.add(node);
}
}
}
@Override
public List<RexNode> getNotSupported() {
return unsupported;
}View on GitHub (pinned to 12126d8942)