go-redis/redis · error

FT.AGGREGATE: ASC and DESC are mutually exclusive

Error message

FT.AGGREGATE: ASC and DESC are mutually exclusive

What it means

Returned by appendFTAggregateStep (the Steps path) when a SortBy field inside an FTAggregateStep.SortBy.Fields entry has both Asc and Desc set to true. A SORTBY field can carry one direction; both is contradictory, so the builder refuses to serialize the step.

Source

Thrown at search_commands.go:766

		args = append(args, step.GroupBy.Fields...)
		for _, reducer := range step.GroupBy.Reduce {
			args = append(args, "REDUCE", reducer.Reducer.String())
			if reducer.Args != nil {
				args = append(args, len(reducer.Args))
				args = append(args, reducer.Args...)
			} else {
				args = append(args, 0)
			}
			if reducer.As != "" {
				args = append(args, "AS", reducer.As)
			}
		}
	case step.SortBy != nil:
		args = append(args, "SORTBY")
		sortByOptions := []interface{}{}
		for _, sortBy := range step.SortBy.Fields {
			if sortBy.Asc && sortBy.Desc {
				return args, fmt.Errorf("FT.AGGREGATE: ASC and DESC are mutually exclusive")
			}
			sortByOptions = append(sortByOptions, sortBy.FieldName)
			if sortBy.Asc {
				sortByOptions = append(sortByOptions, "ASC")
			}
			if sortBy.Desc {
				sortByOptions = append(sortByOptions, "DESC")
			}
		}
		args = append(args, len(sortByOptions))
		args = append(args, sortByOptions...)
		if step.SortBy.Max > 0 {
			args = append(args, "MAX", step.SortBy.Max)
		}
	}
	return args, nil
}

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Set at most one of Asc or Desc per FTAggregateSortBy (leave both false for server-default ASC).
  2. Audit the construction of step.SortBy.Fields to enforce mutual exclusion.
  3. Map a single direction enum to Asc xor Desc before building the step.

Example fix

// before
{SortBy: &FTAggregateSortStep{Fields: []FTAggregateSortBy{{FieldName: "price", Asc: true, Desc: true}}}}
// after
{SortBy: &FTAggregateSortStep{Fields: []FTAggregateSortBy{{FieldName: "price", Desc: true}}}}
Defensive patterns

Strategy: validation

Validate before calling

func validateStepSortDirections(s *FTAggregateSortStep) error {
	for i, f := range s.Fields {
		if f.Asc && f.Desc {
			return fmt.Errorf("SortBy.Fields[%d]: Asc and Desc both set", i)
		}
	}
	return nil
}

Type guard

func directionUnique(f FTAggregateSortBy) bool { return !(f.Asc && f.Desc) }

Prevention

When it happens

Trigger: FTAggregateStep{SortBy: &FTAggregateSortStep{Fields: []FTAggregateSortBy{{FieldName: "price", Asc: true, Desc: true}}}}. Triggered while building the SORTBY token list for a Step.

Common situations: Defaulting both flags true. UI toggles that allow both ASC and DESC selected. Reusing a SortBy value and flipping one flag without clearing the other.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/9cce9db25af69e09.json. Report an issue: GitHub.