go-redis/redis · error
FT.AGGREGATE: Steps cannot be combined with the deprecated L
Error message
FT.AGGREGATE: Steps cannot be combined with the deprecated Load, Apply, GroupBy, SortBy and SortByMax fields
What it means
Returned by validateFTAggregateOptions (via FTAggregateQuery) when FTAggregateOptions.Steps is non-empty AND any of the deprecated top-level fields (Load, Apply, GroupBy, SortBy, SortByMax) is also set. The library exposes two FT.AGGREGATE APIs: the newer Steps-based pipeline and the older flat Load/Apply/GroupBy/SortBy fields; they cannot be mixed in one call because they would serialize conflicting pipeline stages.
Source
Thrown at search_commands.go:691
// FTAggregate - Performs a search query on an index and applies a series of aggregate transformations to the result.
// The 'index' parameter specifies the index to search, and the 'query' parameter specifies the search query.
// For more information, please refer to the Redis documentation:
// [FT.AGGREGATE]: (https://redis.io/commands/ft.aggregate/)
func (c cmdable) FTAggregate(ctx context.Context, index string, query string) *MapStringInterfaceCmd {
args := []interface{}{"FT.AGGREGATE", index, query}
cmd := NewMapStringInterfaceCmd(ctx, args...)
_ = c(ctx, cmd)
return cmd
}
// validateFTAggregateOptions validates mutually exclusive combinations of
// FTAggregateOptions fields before any command arguments are constructed.
func validateFTAggregateOptions(options *FTAggregateOptions) error {
if len(options.Steps) > 0 {
if options.Load != nil || options.Apply != nil || options.GroupBy != nil ||
options.SortBy != nil || options.SortByMax != 0 {
return fmt.Errorf("FT.AGGREGATE: Steps cannot be combined with the deprecated Load, Apply, GroupBy, SortBy and SortByMax fields")
}
if options.LoadAll {
for _, step := range options.Steps {
if step.Load != nil {
return fmt.Errorf("FT.AGGREGATE: LOADALL and LOAD are mutually exclusive")
}
}
}
}
if options.LoadAll && options.Load != nil {
return fmt.Errorf("FT.AGGREGATE: LOADALL and LOAD are mutually exclusive")
}
return nil
}
// appendFTAggregateStep appends the Redis command arguments for a single
// aggregation pipeline step. Each step must set exactly one of Load, Apply,
// GroupBy or SortBy.View on GitHub (pinned to 36d97525cd)
Solutions
- Pick one API: move all pipeline stages into Steps and clear Load/Apply/GroupBy/SortBy/SortByMax, OR remove Steps and use the deprecated fields exclusively.
- Audit the FTAggregateOptions literal at the call site to ensure only one pipeline representation is populated.
- If migrating incrementally, zero out the deprecated fields in the same change that adds Steps.
Example fix
// before
opts := &FTAggregateOptions{
Steps: []FTAggregateStep{{GroupBy: &FTAggregateGroupBy{Fields: []string{"cat"}}}},
SortBy: []FTAggregateSortBy{{FieldName: "price", Desc: true}}, // deprecated, conflicts
}
// after
opts := &FTAggregateOptions{
Steps: []FTAggregateStep{
{GroupBy: &FTAggregateGroupBy{Fields: []string{"cat"}}},
{SortBy: &FTAggregateSortStep{Fields: []FTAggregateSortBy{{FieldName: "price", Desc: true}}}},
},
} Defensive patterns
Strategy: validation
Validate before calling
func validateAggregateOptionsMixed(opts *FTAggregateOptions) error {
if len(opts.Steps) == 0 { return nil }
if opts.Load != nil || opts.Apply != nil || opts.GroupBy != nil || opts.SortBy != nil || opts.SortByMax != 0 {
return fmt.Errorf("do not mix Steps with deprecated Load/Apply/GroupBy/SortBy/SortByMax")
}
return nil
} Type guard
func usesStepsOnly(opts *FTAggregateOptions) bool {
return len(opts.Steps) > 0 &&
opts.Load == nil && opts.Apply == nil && opts.GroupBy == nil &&
opts.SortBy == nil && opts.SortByMax == 0
} Prevention
- Commit to one FT.AGGREGATE API per codebase module: Steps or the deprecated flat fields, not both.
- When migrating, clear the deprecated fields in the same change that introduces Steps.
- Add a unit test asserting the options struct your app builds satisfies usesStepsOnly (or its deprecated equivalent).
When it happens
Trigger: Building FTAggregateOptions with both Steps populated and any of Load/Apply/GroupBy/SortBy/SortByMax non-zero. Triggered in FTAggregateQuery (and the AggregateCmd builder) before any Redis argument is emitted.
Common situations: Partially migrating from the deprecated flat API to Steps and leaving a stale SortBy or GroupBy set. Copy-pasting an options struct that already had GroupBy and appending a Steps entry. Default struct initialization populating both paths.
Related errors
- redis: FT.AGGREGATE COLLECT: empty field name in SortBy
- redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclu
- FT.AGGREGATE: LOADALL and LOAD are mutually exclusive
- FT.AGGREGATE: each step must set exactly one of Load, Apply,
- FT.AGGREGATE: ASC and DESC are mutually exclusive
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/28250e5dabcacb45.json.
Report an issue: GitHub.