pola-rs/polars · error · TypeError

invalid predicate for `filter`: {err}

Error message

invalid predicate for `filter`: {err}

What it means

LazyFrame.filter() accepts Polars expressions, strings naming a schema column, or boolean masks in supported positions. If a predicate is (or a sequence contains) something else — typically a pl.Series or plain Python value — polars raises TypeError showing the offending object. String predicates must name an existing column in collect_schema().

Source

Thrown at py-polars/src/polars/lazyframe/frame.py:4695

            # note: identify masks separately from predicates
            if is_bool_sequence(p, include_series=True):
                boolean_masks.append(pl.Series(p, dtype=Boolean))
            elif (
                (is_seq := is_sequence(p))
                and any(not isinstance(x, pl.Expr) for x in p)
            ) or (
                not is_seq
                and not isinstance(p, pl.Expr)
                and not (isinstance(p, str) and p in self.collect_schema())
            ):
                err = (
                    f"Series(…, dtype={p.dtype})"
                    if isinstance(p, pl.Series)
                    else repr(p)
                )
                msg = f"invalid predicate for `filter`: {err}"
                raise TypeError(msg)
            else:
                all_predicates.extend(
                    wrap_expr(x) for x in parse_into_list_of_expressions(p)
                )

        # unpack equality constraints from kwargs
        all_predicates.extend(
            F.col(name).eq(value) for name, value in constraints.items()
        )
        if not (all_predicates or boolean_masks):
            msg = "at least one predicate or constraint must be provided"
            raise TypeError(msg)

        # if multiple predicates, combine as 'horizontal' expression
        combined_predicate = (
            (
                F.all_horizontal(*all_predicates)
                if len(all_predicates) > 1

View on GitHub (pinned to df599052da)

Solutions

  1. Convert Series masks to expressions: lf.filter(pl.col('a').is_in(series)) or compare directly
  2. For string predicates, confirm the name exists in lf.collect_schema().names()
  3. Validate each predicate with isinstance(p, pl.Expr) before adding it to a dynamic list
  4. Use keyword constraints for equality: lf.filter(country='NL') instead of raw values

Example fix

# before
mask = pl.Series([True, False, True])
lf2 = lf.filter(mask)

# after
lf2 = lf.filter(pl.col('a') > 5)
Defensive patterns

Strategy: type-guard

Validate before calling

import polars as pl
schema_names = set(lf.collect_schema().names())
preds = [p for p in raw_predicates if isinstance(p, pl.Expr) or (isinstance(p, str) and p in schema_names)]
if preds:
    lf = lf.filter(*preds)

Type guard

def is_valid_predicate(p, schema_names: set[str]) -> bool:
    import polars as pl
    return isinstance(p, pl.Expr) or (isinstance(p, str) and p in schema_names)

Try / catch

try:
    lf = lf.filter(*preds)
except TypeError as e:
    if 'invalid predicate' in str(e):
        # log offending predicates and fall back to expression-only set
        lf = lf.filter(*(p for p in preds if isinstance(p, pl.Expr)))
    else:
        raise

Prevention

When it happens

Trigger: lf.filter(pl.Series([True, False])) on a LazyFrame (Series positional masks are not valid lazily); lf.filter('nonexistent_column'); lf.filter([pl.col('a') > 1, 'or']) mixing invalid items; passing a numpy array or plain bool.

Common situations: Reusing DataFrame filter code (where boolean Series masks work) on lazy frames; dynamic predicate lists built from user input where a None or raw value sneaks in; column renames making a string predicate stale.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/a1b3be8a3b272ca8. Report an issue: GitHub.