redis/go-redis · error
FT.AGGREGATE: SortByMax must follow a SortBy step
Error message
FT.AGGREGATE: SortByMax must follow a SortBy step
What it means
FT.AGGREGATE's SortByMax must be applied to a SORTBY step that was already added via SortBy or Steps. The AggregateBuilder checks that the last step is a SORTBY step before setting MAX on it; otherwise it records this error on the builder and Run will fail. This is a builder-ordering contract, not a server error.
Source
Thrown at search_builders.go:366
// regardless of position in the pipeline.
func (b *AggregateBuilder) SortBy(field string, asc bool) *AggregateBuilder {
sb := FTAggregateSortBy{FieldName: field, Asc: asc, Desc: !asc}
if n := len(b.options.Steps); n > 0 && b.options.Steps[n-1].SortBy != nil {
b.options.Steps[n-1].SortBy.Fields = append(b.options.Steps[n-1].SortBy.Fields, sb)
return b
}
b.options.Steps = append(b.options.Steps, FTAggregateStep{
SortBy: &FTAggregateSortByStep{Fields: []FTAggregateSortBy{sb}},
})
return b
}
// SortByMax sets MAX <n> on the last SORTBY step. The last step must be a
// SORTBY; otherwise Run will return an error.
func (b *AggregateBuilder) SortByMax(max int) *AggregateBuilder {
n := len(b.options.Steps)
if n == 0 || b.options.Steps[n-1].SortBy == nil {
b.setErr(fmt.Errorf("FT.AGGREGATE: SortByMax must follow a SortBy step"))
return b
}
b.options.Steps[n-1].SortBy.Max = max
return b
}
// Filter sets FILTER <expr>.
func (b *AggregateBuilder) Filter(expr string) *AggregateBuilder {
b.options.Filter = expr
return b
}
// WithCursor enables WITHCURSOR [COUNT <n>] [MAXIDLE <ms>].
func (b *AggregateBuilder) WithCursor(count, maxIdle int) *AggregateBuilder {
b.options.WithCursor = true
if b.options.WithCursorOptions == nil {
b.options.WithCursorOptions = &FTAggregateWithCursor{}
}View on GitHub (pinned to c5cad058c7)
Solutions
- Call SortBy (or add a SortBy step) immediately before SortByMax so the last step is SORTBY
- Remove the SortByMax call if you never intend to sort
- Use the new Steps API with a single SortBy step carrying the Max field instead of SortByMax
Example fix
// before
b := client.FTAggregateWithArgs(idx, q).
GroupBy(...).
SortByMax(5)
// after
b := client.FTAggregateWithArgs(idx, q).
GroupBy(...).
SortBy(&redis.FTAggregateSortBy{FieldName: "@score"}).
SortByMax(5) Defensive patterns
Strategy: validation
Validate before calling
steps := len(b.options.Steps)
if steps == 0 || b.options.Steps[steps-1].SortBy == nil {
return fmt.Errorf("SortByMax requires a preceding SortBy step")
} Prevention
- Always place SortByMax immediately after a SortBy call in builder chains
- Prefer the Steps API where Max is a field of the SortBy step
- Check builder.Err() before calling Run
When it happens
Trigger: Calling b.SortByMax(n) before calling b.SortBy(...), or calling it after any non-SortBy step (e.g. after Apply, GroupBy, Filter) was appended, so b.options.Steps is empty or the last step has no SortBy.
Common situations: Refactoring from the deprecated SortByMax field on FTAggregateOptions to the step-based builder and calling SortByMax out of order; chaining builder methods in the wrong sequence.
Related errors
- redis: FT.AGGREGATE COLLECT: empty field name in Fields
- redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empt
- redis: FT.AGGREGATE COLLECT: empty field name in SortBy
- redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclu
- FT.AGGREGATE: Steps cannot be combined with the deprecated L
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/703bf1a4de229e4b.
Report an issue: GitHub.