risingwavelabs/risingwave · error
Filter can only receive bool array
Error message
Filter can only receive bool array
What it means
The stream aggregate executor evaluates a user-defined filter expression over a chunk and expects the result to be a boolean array used as a visibility mask. `agg_call_filter_res` bails with this error when the evaluated filter result is not a bool array, since it cannot be converted into a visibility bitmap.
Source
Thrown at src/stream/src/executor/aggregate/mod.rs:105
agg_call.agg_type,
AggType::Builtin(PbAggKind::Min | PbAggKind::Max | PbAggKind::StringAgg)
) {
// should skip NULL value for these kinds of agg function
let agg_col_idx = agg_call.args.val_indices()[0]; // the first arg is the agg column for all these kinds
let agg_col_bitmap = chunk.column_at(agg_col_idx).null_bitmap();
vis &= agg_col_bitmap;
}
if let Some(ref filter) = agg_call.filter {
// TODO: should we build `filter` in non-strict mode?
if let Bool(filter_res) = NonStrictExpression::new_topmost(filter.clone(), LogReport)
.eval_infallible(chunk)
.await
.as_ref()
{
vis &= filter_res.to_bitmap();
} else {
bail!("Filter can only receive bool array");
}
}
Ok(vis)
}
fn iter_table_storage<S>(
state_storages: &mut [AggStateStorage<S>],
) -> impl Iterator<Item = &mut StateTable<S>>
where
S: StateStore,
{
state_storages
.iter_mut()
.filter_map(|storage| match storage {
AggStateStorage::Value => None,
AggStateStorage::MaterializedInput { table, .. } => Some(table),
})View on GitHub (pinned to 6469eb736d)
Solutions
- Check the CREATE MATERIALIZED VIEW / aggregate query and make the FILTER clause expression explicitly boolean, e.g. `FILTER (WHERE (x)::boolean)` or `FILTER (WHERE x = 1)`.
- Inspect the plan (`EXPLAIN`) to see what expression is bound to the aggregate filter and fix its type in SQL.
- If the query is fine, collect the internal error and file/upgrade — this indicates a frontend type-checking gap.
- If it started after a version upgrade of RisingWave, recreate the materialized view so plans are re-planned with the current frontend.
Example fix
// before SELECT count(*) FILTER (WHERE status) FROM t; // status is int // after SELECT count(*) FILTER (WHERE status != 0) FROM t;
Defensive patterns
Strategy: validation
Validate before calling
-- before creating an aggregate with FILTER, verify the predicate is boolean SELECT pg_typeof(status) FROM t LIMIT 0; -- must return boolean for FILTER (WHERE status) -- or force it: FILTER (WHERE (expr)::boolean)
Prevention
- Always write FILTER predicates as explicit boolean comparisons (`x = 1`, `x IS NOT NULL`), never bare non-boolean columns.
- Run EXPLAIN on queries with FILTER clauses to confirm the planned expression type.
- Recreate materialized views after upgrading RisingWave so plans match executor expectations.
When it happens
Trigger: A `FILTER (WHERE ...)` clause on an aggregate (or an optimizer-inserted filter) whose expression type-checks in the frontend but evaluates to a non-boolean array at runtime in the streaming engine, e.g. a NULL-typed or non-bool projection reaching the aggregate filter slot.
Common situations: Frontend/stream type mismatch after planner bugs, expressions like `filter (where x)` where x is an integer, or state-restored plans created by an older RisingWave version whose schema drifted from the current executor expectations.
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
- dynamic filter condition eval must return bool array
- Time column should be Timestamp or Timestamptz
- Chunk operation error: {0}
- unmatched type: filter expr returns a non-null array
- MATCH_RECOGNIZE WITHIN deadline has type {} but the ORDER BY
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/adf02757814e8c70.
Report an issue: GitHub.