redis/redis-py · error · ValueError
collect sort_by must contain at least one field
Error message
collect sort_by must contain at least one field
What it means
Raised by the collect reducer when sort_by is provided as an iterable but contains no Asc/Desc entries. Sorting within COLLECT requires at least one field directive; an empty iterable is a no-op the library rejects rather than silently dropping the SORTBY clause.
Source
Thrown at redis/commands/search/reducers.py:253
if not names or any(not n.strip() for n in names):
raise ValueError(
"collect fields must be '*' or a non-empty list of names"
)
names = [_ensure_at_prefix(n) for n in names]
args += ["FIELDS", str(len(names))] + names
# DISTINCT (optional)
if distinct:
args += ["DISTINCT"]
# SORTBY (optional)
if sort_by is not None:
sort_fields = [sort_by] if isinstance(sort_by, (Asc, Desc)) else sort_by
sort_args: list[str] = []
for f in sort_fields:
sort_args += [_ensure_at_prefix(f.field), f.DIRSTRING]
if not sort_args:
raise ValueError("collect sort_by must contain at least one field")
args += ["SORTBY", str(len(sort_args))] + sort_args
# LIMIT (optional)
if limit is not None:
offset, count = limit
args += ["LIMIT", str(offset), str(count)]
super().__init__(*args)
View on GitHub (pinned to da03cdc7e8)
Solutions
- Pass at least one Asc/Desc instance: from redis.commands.search.aggregation import Asc, Desc; collect(fields='*', sort_by=Asc('price')).
- If sorting is optional, omit sort_by entirely (pass None) when there is nothing to sort by.
- Guard dynamic inputs: only pass sort_by when the list is non-empty.
Example fix
// before collect(fields='*', sort_by=sort_dirs or []) // after collect(fields='*', sort_by=sort_dirs if sort_dirs else None)
Defensive patterns
Strategy: validation
Validate before calling
def safe_sort_by(sort_dirs):
if not sort_dirs:
return None
if isinstance(sort_dirs, (Asc, Desc)):
return sort_dirs
return list(sort_dirs) if len(list(sort_dirs)) else None
# usage: collect(fields='*', sort_by=safe_sort_by(dirs)) Type guard
from redis.commands.search.aggregation import Asc, Desc
def has_sort_entries(sort_by) -> bool:
if sort_by is None:
return True
if isinstance(sort_by, (Asc, Desc)):
return True
return len(list(sort_by)) > 0 Try / catch
try:
collect(fields='*', sort_by=dirs)
except ValueError:
collect(fields='*', sort_by=None) Prevention
- Pass None instead of an empty list when there is nothing to sort by.
- Materialize generators before checking length.
- Keep sort_by optional in your config schema.
When it happens
Trigger: collect(fields='*', sort_by=[]) or collect(fields='*', sort_by=sort_dirs) where sort_dirs is an empty list/generator.
Common situations: Building sort directives dynamically from user choices that resolved to none; unpacking an empty list into sort_by; refactoring that left a default empty list.
Related errors
- collect fields must be '*' or a non-empty list of names
- Did not receive a SortByField.
- index_type must be one of {list(IndexType)}
- prefix must be provided
- Did not receive a Filter object.
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/e177c6e184b3d5ca.json.
Report an issue: GitHub.