{"record":{"id":"edf312f295d0ecec","repo":"redis/redis-rb","slug":"collect-fields-must-be-all-or-a-non-empty-list","errorCode":null,"errorMessage":"collect fields must be :all or a non-empty list","messagePattern":"collect fields must be :all or a non-empty list","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/redis/commands/modules/search/aggregation.rb","lineNumber":353,"sourceCode":"        #   +LIMIT <offset> <count>+; with +sort_by+ this is a bounded top-N selection\n        # @param alias_name [String, nil] the reducer output column name (+AS+)\n        # @return [Reducers]\n        # @raise [ArgumentError] if +fields+ is an empty list and not +:all+\n        def self.collect(fields:, distinct: false, sort_by: nil, limit: nil, alias_name: nil)\n          tokens = collect_fields_tokens(fields)\n          tokens << \"DISTINCT\" if distinct\n          tokens.concat(collect_sortby_tokens(sort_by))\n          tokens.concat([\"LIMIT\", *limit]) if limit\n\n          new(\"COLLECT\", *tokens, alias_name: alias_name)\n        end\n\n        # Render the +FIELDS+ clause tokens for {collect}.\n        def self.collect_fields_tokens(fields)\n          return [\"FIELDS\", \"*\"] if fields == :all\n\n          fields = Array(fields)\n          raise ArgumentError, \"collect fields must be :all or a non-empty list\" if fields.empty?\n\n          [\"FIELDS\", fields.size.to_s, *fields]\n        end\n        private_class_method :collect_fields_tokens\n\n        # Render the optional +SORTBY+ clause tokens for {collect}. Each Asc/Desc wrapper emits a\n        # name and its direction (2 tokens); a plain String emits just the name (ASC is implicit).\n        def self.collect_sortby_tokens(sort_by)\n          return [] if sort_by.nil? || sort_by.empty?\n\n          sort_tokens = sort_by.flat_map do |field|\n            field.is_a?(Asc) || field.is_a?(Desc) ? [field.name, field.order] : [field]\n          end\n          [\"SORTBY\", sort_tokens.size.to_s, *sort_tokens]\n        end\n        private_class_method :collect_sortby_tokens\n\n        # @return [String] the reducer function name","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/redis/redis-rb/blob/2ba9010b91dab9e0fde1fbae3a9aae003f8bc307/lib/redis/commands/modules/search/aggregation.rb#L335-L371","documentation":"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 [].","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nReducers.collect(fields: picked, alias_name: \"rows\") # picked == []\n// after\nReducers.collect(fields: picked.empty? ? :all : picked, alias_name: \"rows\")","handlingStrategy":"validation","validationCode":"def collect_reducer(fields:, **opts)\n  fields = :all if fields.nil? || (fields.respond_to?(:empty?) && fields.empty?)\n  Reducers.collect(fields: fields, **opts)\nend","typeGuard":"fields == :all || (fields.is_a?(Array) && !fields.empty?)","tryCatchPattern":null,"preventionTips":["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 []"],"tags":["redis-search","ft-aggregate","collect","argumenterror","reducers"],"backgroundTag":"empty-list-argument","analyzedSha":"2ba9010b91dab9e0fde1fbae3a9aae003f8bc307","analyzedAt":"2026-08-23T03:54:57.017Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}