redis/redis-py · error · ValueError
collect fields must be '*' or a non-empty list of names
Error message
collect fields must be '*' or a non-empty list of names
What it means
Raised by the collect reducer constructor when the fields argument is a list/iterable that is empty or contains blank (whitespace-only) names. COLLECT projects fields from each grouped row, so at least one real field name (or the '*' wildcard) is mandatory. The literal '*' is handled separately and bypasses this check.
Source
Thrown at redis/commands/search/reducers.py:236
- **distinct**: When ``True``, emit ``DISTINCT`` to deduplicate entries
with identical projected fields. Forward-compatible: this option is
not yet implemented by the server and currently produces a server
error when sent.
- **sort_by**: An ``Asc``/``Desc`` instance or an iterable of them, used
to order the collected entries within each group.
- **limit**: An ``(offset, count)`` pair. Returns at most ``count``
entries per group after skipping ``offset``. With ``sort_by`` this
acts as a top-N selection.
"""
args: list[str] = []
# FIELDS (required)
if fields == "*":
args += ["FIELDS", "*"]
else:
names = [fields] if isinstance(fields, str) else list(fields)
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_argsView on GitHub (pinned to da03cdc7e8)
Solutions
- Pass '*' to project every field: collect(fields='*').
- Supply a non-empty list of real names: collect(fields=['price', 'name']).
- Validate before constructing: collect(fields=names) only when names and all(n.strip() for n in names).
Example fix
// before collect(fields=selected or []) // after collect(fields=selected if selected else '*')
Defensive patterns
Strategy: validation
Validate before calling
def coerce_collect_fields(fields):
if fields in (None, '', []):
return '*'
if isinstance(fields, str):
return fields
names = [n for n in fields if n and n.strip()]
return names if names else '*'
# usage: collect(fields=coerce_collect_fields(raw)) Type guard
def valid_collect_fields(fields) -> bool:
if fields == '*':
return True
names = [fields] if isinstance(fields, str) else list(fields or [])
return bool(names) and all(n.strip() for n in names) Try / catch
try:
collect(fields=raw_fields)
except ValueError:
collect(fields='*') Prevention
- Default to '*' when the field list is empty.
- Strip/validate names before constructing the reducer.
- Test aggregation builders with empty field selections.
When it happens
Trigger: collect(fields=[]) or collect(fields=['']) or collect(fields=['a', ' ']). Also collect(fields=names) where names resolved to an empty list at runtime.
Common situations: Dynamically generating the field list from user selection or schema introspection that returned nothing; stripping names and producing blanks; passing an empty generator.
Related errors
- collect sort_by must contain at least one field
- index_type must be one of {list(IndexType)}
- prefix must be provided
- Did not receive a Filter object.
- Did not receive a SortByField.
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/bd11357e53e16767.json.
Report an issue: GitHub.