go-redis/redis · error
FT.AGGREGATE: LOADALL and LOAD are mutually exclusive
Error message
FT.AGGREGATE: LOADALL and LOAD are mutually exclusive
What it means
Returned by validateFTAggregateOptions when LoadAll is true and any individual step in Steps contains a Load field. LOADALL emits a single LOAD * on the wire, which is semantically incompatible with per-step LOAD clauses; the builder rejects the combination up front.
Source
Thrown at search_commands.go:696
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.
func appendFTAggregateStep(args []interface{}, step FTAggregateStep) ([]interface{}, error) {
set := 0
if step.Load != nil {
set++
}View on GitHub (pinned to 36d97525cd)
Solutions
- Drop LoadAll and express all LOADs as step-level Load entries, or keep LoadAll and remove every step-level Load.
- Audit the Steps slice to confirm no FTAggregateStep.Load is set when LoadAll is true.
- Prefer LoadAll only when you genuinely want every field and have no per-step LOAD requirements.
Example fix
// before
opts := &FTAggregateOptions{
LoadAll: true,
Steps: []FTAggregateStep{{Load: &FTAggregateLoad{Field: "price"}}},
}
// after (option A: keep LoadAll)
opts := &FTAggregateOptions{LoadAll: true, Steps: []FTAggregateStep{{Apply: ...}}}
// after (option B: explicit step LOADs)
opts := &FTAggregateOptions{Steps: []FTAggregateStep{{Load: &FTAggregateLoad{Field: "price"}}}} Defensive patterns
Strategy: validation
Validate before calling
func validateLoadAllVsStepLoads(opts *FTAggregateOptions) error {
if !opts.LoadAll { return nil }
for i, st := range opts.Steps {
if st.Load != nil {
return fmt.Errorf("Steps[%d] has Load while LoadAll is set", i)
}
}
return nil
} Prevention
- Treat LoadAll as exclusive: never also set a step-level Load.
- Prefer LoadAll only when you genuinely want every field; otherwise enumerate step LOADs and leave LoadAll false.
- Audit options literals during code review for the LoadAll + step.Load combination.
When it happens
Trigger: Setting FTAggregateOptions{LoadAll: true, Steps: []FTAggregateStep{{Load: &FTAggregateLoad{Field: "price"}}}}. Triggered during option validation before serialization.
Common situations: Enabling LoadAll for convenience while still hand-specifying a step-level LOAD. Migrating LOAD clauses into Steps without clearing the LoadAll flag. Copy-pasting options that already had LoadAll enabled.
Related errors
- 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
- 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/f6c29d502bb71c14.json.
Report an issue: GitHub.