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

  1. 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)`.
  2. Inspect the plan (`EXPLAIN`) to see what expression is bound to the aggregate filter and fix its type in SQL.
  3. If the query is fine, collect the internal error and file/upgrade — this indicates a frontend type-checking gap.
  4. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/adf02757814e8c70. Report an issue: GitHub.