redis/redis-py · error · AttributeError

Did not receive a Filter object.

Error message

Did not receive a Filter object.

What it means

Raised during Query.get_args() / _get_args_tags() when an entry in the query's filter list is not an instance of redis.commands.search.query.Filter (NumericFilter or GeoFilter). Query.add_filter accepts any object, so a wrong type is caught only at argument-serialization time.

Solutions

  1. Pass a NumericFilter or GeoFilter instance to add_filter, e.g. query.add_filter(NumericFilter('price', 0, 100)).
  2. If you have a raw querystring expression, put it in the Query's query string instead of add_filter.
  3. Build filters via the documented helper classes (GeoFilter, NumericFilter) rather than tuples.

Example fix

// before
query.add_filter(('FILTER', 'price', 0, 100))
// after
from redis.commands.search.query import NumericFilter
query.add_filter(NumericField('price', 0, 100))
# correct class name:
query.add_filter(NumericFilter('price', 0, 100))
Defensive patterns

Strategy: type-guard

Validate before calling

from redis.commands.search.query import Filter
for flt in filters:
    assert isinstance(flt, Filter), f'expected Filter, got {type(flt)}'
    query.add_filter(flt)

Type guard

from redis.commands.search.query import Filter

def is_filter(f) -> bool:
    return isinstance(f, Filter)

Try / catch

try:
    query.get_args()
except AttributeError as e:
    if 'Filter object' in str(e):
        # rebuild filters as Filter instances
        raise
    raise

Prevention

When it happens

Trigger: Calling query.add_filter(x) where x is a raw tuple, dict, string, or None instead of a Filter subclass. Mutating Query._filters directly with non-Filter items.

Common situations: Passing a querystring filter expression instead of the Filter object. Copy-paste from examples that build filters inline. Storing filters in a list and appending the wrong shape.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/1a4861e89e6028a9. Report an issue: GitHub.

Appendix: source

Thrown at redis/commands/search/query.py:217

        args += ["LIMIT", self._offset, self._num]
        return args

    def _get_args_tags(self) -> List[Union[str, int, float]]:
        args: List[Union[str, int, float]] = []
        if self._no_content:
            args.append("NOCONTENT")
        if self._fields:
            args.append("INFIELDS")
            args.append(len(self._fields))
            args += self._fields
        if self._verbatim:
            args.append("VERBATIM")
        if self._no_stopwords:
            args.append("NOSTOPWORDS")
        if self._filters:
            for flt in self._filters:
                if not isinstance(flt, Filter):
                    raise AttributeError("Did not receive a Filter object.")
                args += flt.args
        if self._with_payloads:
            args.append("WITHPAYLOADS")
        if self._scorer:
            args += ["SCORER", self._scorer]
        if self._with_scores:
            args.append("WITHSCORES")
        if self._ids:
            args.append("INKEYS")
            args.append(len(self._ids))
            args += self._ids
        if self._slop >= 0:
            args += ["SLOP", self._slop]
        if self._timeout is not None:
            args += ["TIMEOUT", self._timeout]
        if self._in_order:
            args.append("INORDER")
        if self._return_fields:

View on GitHub (pinned to 6a6b581b48)