{"id":"a76cebf1600aa2a8","repo":"go-redis/redis","slug":"redis-ft-aggregate-collect-requires-fieldsall-or","errorCode":null,"errorMessage":"redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empty Fields list","messagePattern":"redis: FT\\.AGGREGATE COLLECT requires FieldsAll or a non-empty Fields list","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"search_collect.go","lineNumber":99,"sourceCode":"// The serializer computes <narg> as len(args), which matches the COLLECT\n// contract: narg counts every FIELDS/DISTINCT/SORTBY/LIMIT token.\nfunc buildCollectArgs(o FTAggregateCollect) ([]interface{}, error) {\n\targs := make([]interface{}, 0, 8)\n\n\t// FIELDS (required): either * or a counted list of @-names.\n\tswitch {\n\tcase o.FieldsAll:\n\t\targs = append(args, \"FIELDS\", \"*\")\n\tcase len(o.Fields) > 0:\n\t\targs = append(args, \"FIELDS\", len(o.Fields))\n\t\tfor _, f := range o.Fields {\n\t\t\tif strings.TrimLeft(f, \"@\") == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT: empty field name in Fields\")\n\t\t\t}\n\t\t\targs = append(args, ensureAtPrefix(f))\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empty Fields list\")\n\t}\n\n\t// DISTINCT (optional, forward-compatible).\n\tif o.Distinct {\n\t\targs = append(args, \"DISTINCT\")\n\t}\n\n\t// SORTBY (optional). sort_narg counts each field plus its optional\n\t// direction token.\n\tif len(o.SortBy) > 0 {\n\t\tsortTokens := make([]interface{}, 0, len(o.SortBy)*2)\n\t\tfor _, s := range o.SortBy {\n\t\t\tif strings.TrimLeft(s.FieldName, \"@\") == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT: empty field name in SortBy\")\n\t\t\t}\n\t\t\tif s.Asc && s.Desc {\n\t\t\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclusive\")\n\t\t\t}","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/search_collect.go#L81-L117","documentation":"Returned from NewCollectReducer when FTAggregateCollect has neither FieldsAll=true nor a non-empty Fields slice. COLLECT must project something (either FIELDS * or an explicit field list); an empty projection is rejected at construction time before any command is sent.","triggerScenarios":"Passing FTAggregateCollect{} (zero value) or FTAggregateCollect{Fields: nil} to AggregateBuilder.Collect or NewCollectReducer. FieldsAll defaults to false and Fields defaults to nil, so the default branch is an error.","commonSituations":"Building FTAggregateCollect conditionally and forgetting to set either FieldsAll or Fields; refactoring that removed the Fields assignment; assuming COLLECT defaults to FIELDS * (it does not).","solutions":["Set FieldsAll=true if you want all pipeline fields projected (FIELDS *), or populate Fields with at least one name.","Add a validation check at construction: require either FieldsAll || len(Fields) > 0.","If unsure which fields exist, use FieldsAll=true (optionally paired with an upstream LOAD *)."],"exampleFix":"// before\ncollect := redis.FTAggregateCollect{} // no FieldsAll, no Fields\nb.GroupBy(\"@order\").Collect(collect)\n\n// after\ncollect := redis.FTAggregateCollect{FieldsAll: true}\nb.GroupBy(\"@order\").Collect(collect)","handlingStrategy":"validation","validationCode":"if !collect.FieldsAll && len(collect.Fields) == 0 {\n    return errors.New(\"COLLECT requires FieldsAll or a non-empty Fields list\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := redis.NewCollectReducer(collect); err != nil {\n    if strings.Contains(err.Error(), \"requires FieldsAll or a non-empty Fields\") {\n        collect.FieldsAll = true // or set Fields explicitly\n    }\n}","preventionTips":["Always initialize FTAggregateCollect with either FieldsAll=true or an explicit Fields slice.","When unsure of the schema, prefer FieldsAll=true paired with an upstream LOAD *.","Unit-test the Collect call path to catch zero-value structs."],"tags":["ftaggregate","search","collect","validation"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}