redis/redis-rb · error · ArgumentError
collect fields must be :all or a non-empty list
Error message
collect fields must be :all or a non-empty list
What it means
The COLLECT reducer in an FT.AGGREGATE GROUPBY pipeline must project fields: either all fields materialized by the pipeline (FIELDS *) via fields: :all, or an explicit list (FIELDS count name...). An empty list has no valid server-side rendering, so Reducers.collect raises ArgumentError when fields is anything that Array() turns into an empty list (lib/redis/commands/modules/search/aggregation.rb:353). fields: nil also raises, because Array(nil) is [].
Source
Thrown at lib/redis/commands/modules/search/aggregation.rb:353
# +LIMIT <offset> <count>+; with +sort_by+ this is a bounded top-N selection
# @param alias_name [String, nil] the reducer output column name (+AS+)
# @return [Reducers]
# @raise [ArgumentError] if +fields+ is an empty list and not +:all+
def self.collect(fields:, distinct: false, sort_by: nil, limit: nil, alias_name: nil)
tokens = collect_fields_tokens(fields)
tokens << "DISTINCT" if distinct
tokens.concat(collect_sortby_tokens(sort_by))
tokens.concat(["LIMIT", *limit]) if limit
new("COLLECT", *tokens, alias_name: alias_name)
end
# Render the +FIELDS+ clause tokens for {collect}.
def self.collect_fields_tokens(fields)
return ["FIELDS", "*"] if fields == :all
fields = Array(fields)
raise ArgumentError, "collect fields must be :all or a non-empty list" if fields.empty?
["FIELDS", fields.size.to_s, *fields]
end
private_class_method :collect_fields_tokens
# Render the optional +SORTBY+ clause tokens for {collect}. Each Asc/Desc wrapper emits a
# name and its direction (2 tokens); a plain String emits just the name (ASC is implicit).
def self.collect_sortby_tokens(sort_by)
return [] if sort_by.nil? || sort_by.empty?
sort_tokens = sort_by.flat_map do |field|
field.is_a?(Asc) || field.is_a?(Desc) ? [field.name, field.order] : [field]
end
["SORTBY", sort_tokens.size.to_s, *sort_tokens]
end
private_class_method :collect_sortby_tokens
# @return [String] the reducer function nameView on GitHub (pinned to 2ba9010b91)
Solutions
- Pass fields: :all when every materialized field should be collected
- Guard dynamic lists: fall back to :all when the computed list is empty
- Validate the column config at load time, where the failure is easier to attribute than at query time
Example fix
// before Reducers.collect(fields: picked, alias_name: "rows") # picked == [] // after Reducers.collect(fields: picked.empty? ? :all : picked, alias_name: "rows")
Defensive patterns
Strategy: validation
Validate before calling
def collect_reducer(fields:, **opts) fields = :all if fields.nil? || (fields.respond_to?(:empty?) && fields.empty?) Reducers.collect(fields: fields, **opts) end
Type guard
fields == :all || (fields.is_a?(Array) && !fields.empty?)
Prevention
- Default empty column configs to :all explicitly
- Validate analytics column lists at config load, not at query time
- Remember nil behaves like [] here because Array(nil) is []
When it happens
Trigger: Reducers.collect(fields: [], alias_name: "rows"); Reducers.collect(fields: nil); a computed field list that is empty at runtime, e.g. fields: columns & allowed where the intersection is empty.
Common situations: Config-driven aggregation column lists that can legitimately be empty; intending project-everything but passing [] instead of :all; refactoring a hardcoded field list into a variable that starts empty.
Related errors
- Invalid phonetic matcher. Supported matchers are: #{valid_ma
- Realtime vector indexing supporting 3 Indexing Methods: 'FLA
- Invalid schema
- nx and xx are mutually exclusive
- fpha accepts only: #{JSON_SET_FPHA_TYPES.join(', ')}
AI-assisted analysis of redis/redis-rb@2ba9010b91 (2026-08-23).
Data as JSON: /api/errors/edf312f295d0ecec.
Report an issue: GitHub.