go-redis/redis · error
redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empt
Error message
redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empty Fields list
What it means
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.
Source
Thrown at search_collect.go:99
// The serializer computes <narg> as len(args), which matches the COLLECT
// contract: narg counts every FIELDS/DISTINCT/SORTBY/LIMIT token.
func buildCollectArgs(o FTAggregateCollect) ([]interface{}, error) {
args := make([]interface{}, 0, 8)
// FIELDS (required): either * or a counted list of @-names.
switch {
case o.FieldsAll:
args = append(args, "FIELDS", "*")
case len(o.Fields) > 0:
args = append(args, "FIELDS", len(o.Fields))
for _, f := range o.Fields {
if strings.TrimLeft(f, "@") == "" {
return nil, fmt.Errorf("redis: FT.AGGREGATE COLLECT: empty field name in Fields")
}
args = append(args, ensureAtPrefix(f))
}
default:
return nil, fmt.Errorf("redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empty Fields list")
}
// DISTINCT (optional, forward-compatible).
if o.Distinct {
args = append(args, "DISTINCT")
}
// SORTBY (optional). sort_narg counts each field plus its optional
// direction token.
if len(o.SortBy) > 0 {
sortTokens := make([]interface{}, 0, len(o.SortBy)*2)
for _, s := range o.SortBy {
if strings.TrimLeft(s.FieldName, "@") == "" {
return nil, fmt.Errorf("redis: FT.AGGREGATE COLLECT: empty field name in SortBy")
}
if s.Asc && s.Desc {
return nil, fmt.Errorf("redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclusive")
}View on GitHub (pinned to 36d97525cd)
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 *).
Example fix
// before
collect := redis.FTAggregateCollect{} // no FieldsAll, no Fields
b.GroupBy("@order").Collect(collect)
// after
collect := redis.FTAggregateCollect{FieldsAll: true}
b.GroupBy("@order").Collect(collect) Defensive patterns
Strategy: validation
Validate before calling
if !collect.FieldsAll && len(collect.Fields) == 0 {
return errors.New("COLLECT requires FieldsAll or a non-empty Fields list")
} Try / catch
if _, err := redis.NewCollectReducer(collect); err != nil {
if strings.Contains(err.Error(), "requires FieldsAll or a non-empty Fields") {
collect.FieldsAll = true // or set Fields explicitly
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- FT.AGGREGATE: Collect must follow a GroupBy step
- redis: FT.AGGREGATE COLLECT: empty field name in Fields
- FT.AGGREGATE: Reduce must follow a GroupBy step
- FT.AGGREGATE: ReduceAs must follow a GroupBy step
- FT.AGGREGATE: SortByMax must follow a SortBy step
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/a76cebf1600aa2a8.json.
Report an issue: GitHub.