redis/redis-py · error · AttributeError

Did not receive a SortByField.

Error message

Did not receive a SortByField.

What it means

Raised during Query._get_args_tags() when Query._sortby is set to something that is not a redis.commands.search.query.SortbyField instance. The public Query.sort_by() method always constructs a SortbyField, so this only fires when _sortby is assigned directly with the wrong type.

Solutions

  1. Use the public setter: query.sort_by('price', asc=False).
  2. If assigning _sortby directly, wrap it: query._sortby = SortbyField('price', asc=False).
  3. Audit custom Query subclasses to ensure they emit SortbyField instances.

Example fix

// before
query._sortby = ('price', 'DESC')
// after
query.sort_by('price', asc=False)
# or
from redis.commands.search.query import SortbyField
query._sortby = SortbyField('price', asc=False)
Defensive patterns

Strategy: validation

Validate before calling

# Always use the public setter
query.sort_by('price', asc=False)
# If assigning _sortby directly:
from redis.commands.search.query import SortbyField
assert isinstance(query._sortby, SortbyField)

Type guard

from redis.commands.search.query import SortbyField

def is_sortby_field(s) -> bool:
    return isinstance(s, SortbyField)

Try / catch

try:
    query.get_args()
except AttributeError as e:
    if 'SortByField' in str(e):
        query.sort_by('price', asc=False)
    else:
        raise

Prevention

When it happens

Trigger: Directly assigning query._sortby = ('price', 'ASC') or a string instead of using Query.sort_by(). Subclassing Query and overriding sort handling without producing a SortbyField.

Common situations: Internal code or tests that bypass the sort_by() setter. Serialization-time discovery of a wrongly typed internal field.

Related errors


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

Appendix: source

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

        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:
            args.append("RETURN")
            args.append(len(self._return_fields))
            args += self._return_fields
        if self._sortby:
            if not isinstance(self._sortby, SortbyField):
                raise AttributeError("Did not receive a SortByField.")
            args.append("SORTBY")
            args += self._sortby.args
        if self._language:
            args += ["LANGUAGE", self._language]
        if self._expander:
            args += ["EXPANDER", self._expander]
        if self._dialect:
            args += ["DIALECT", self._dialect]

        return args

    def paging(self, offset: int, num: int) -> "Query":
        """
        Set the paging for the query (defaults to 0..10).

        - **offset**: Paging offset for the results. Defaults to 0
        - **num**: How many results do we want
        """

View on GitHub (pinned to 6a6b581b48)