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

  1. Call SortBy (or add a SortBy step) immediately before SortByMax so the last step is SORTBY
  2. Remove the SortByMax call if you never intend to sort
  3. 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

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


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/703bf1a4de229e4b. Report an issue: GitHub.