deepset-ai/haystack · error · FilterError

Filter value must be a `list` when using operator 'in' or 'n

Error message

Filter value must be a `list` when using operator 'in' or 'not in', received type '{type(filter_value)}'

What it means

The 'in' and 'not in' operators require the filter value to be a list; _in raises FilterError for any other type. Since _not_in delegates to _in, both operators enforce this.

Source

Thrown at haystack/utils/filters.py:247

def _less_than_equal(value: Any, filter_value: Any, strict_datetime_comparison: bool) -> bool:
    if value is None or filter_value is None:
        # We can't compare None values reliably using operators '>', '>=', '<', '<='
        return False

    value, filter_value, comparable = _prepare_ordering_comparison(
        value=value, filter_value=filter_value, strict_datetime_comparison=strict_datetime_comparison
    )
    if not comparable:
        return False
    return value <= filter_value


def _in(value: Any, filter_value: Any, strict_datetime_comparison: bool) -> bool:
    if not isinstance(filter_value, list):
        msg = (
            f"Filter value must be a `list` when using operator 'in' or 'not in', received type '{type(filter_value)}'"
        )
        raise FilterError(msg)
    return any(_equal(e, value, strict_datetime_comparison) for e in filter_value)


def _not_in(value: Any, filter_value: Any, strict_datetime_comparison: bool) -> bool:
    return not _in(value=value, filter_value=filter_value, strict_datetime_comparison=strict_datetime_comparison)


COMPARISON_OPERATORS = {
    "==": _equal,
    "!=": _not_equal,
    ">": _greater_than,
    ">=": _greater_than_equal,
    "<": _less_than,
    "<=": _less_than_equal,
    "in": _in,
    "not in": _not_in,
}

View on GitHub (pinned to e318778c9b)

Solutions

  1. Wrap the value in a list, e.g. ["news"].
  2. Use '==' or '!=' if you actually mean single-value equality.
  3. Validate that 'in'/'not in' filter values are lists before applying filters.

Example fix

// before
filters = {"operator": "in", "field": "meta.tag", "value": "news"}
// after
filters = {"operator": "in", "field": "meta.tag", "value": ["news"]}
Defensive patterns

Strategy: validation

Validate before calling

if f.get("operator") in {"in", "not in"} and not isinstance(f.get("value"), list):
    f["value"] = [f["value"]]

Type guard

def is_list_value(f: dict) -> bool:
    return f.get("operator") not in {"in", "not in"} or isinstance(f.get("value"), list)

Try / catch

try:
    ok = document_matches_filter(doc, filters)
except FilterError as e:
    logger.warning("invalid filter: %s", e)
    ok = False

Prevention

When it happens

Trigger: Filters like {"operator": "in", "field": "meta.tag", "value": "news"} (a bare string) or a dict/int value.

Common situations: Forgetting to wrap a single value in a list when switching from '==' to 'in'; programmatic filter builders that pass scalars through.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/f703f90e3f2ccf39. Report an issue: GitHub.