{"record":{"id":"4527fc81f0e04b61","repo":"redis/go-redis","slug":"redis-ft-aggregate-collect-asc-and-desc-are-mutu","errorCode":null,"errorMessage":"redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclusive","messagePattern":"redis: FT\\.AGGREGATE COLLECT: ASC and DESC are mutually exclusive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"search_collect.go","lineNumber":116,"sourceCode":"\tdefault:\n\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT requires FieldsAll or a non-empty Fields list\")\n\t}\n\n\t// DISTINCT (optional, forward-compatible).\n\tif o.Distinct {\n\t\targs = append(args, \"DISTINCT\")\n\t}\n\n\t// SORTBY (optional). sort_narg counts each field plus its optional\n\t// direction token.\n\tif len(o.SortBy) > 0 {\n\t\tsortTokens := make([]interface{}, 0, len(o.SortBy)*2)\n\t\tfor _, s := range o.SortBy {\n\t\t\tif strings.TrimLeft(s.FieldName, \"@\") == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT: empty field name in SortBy\")\n\t\t\t}\n\t\t\tif s.Asc && s.Desc {\n\t\t\t\treturn nil, fmt.Errorf(\"redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclusive\")\n\t\t\t}\n\t\t\tsortTokens = append(sortTokens, ensureAtPrefix(s.FieldName))\n\t\t\tswitch {\n\t\t\tcase s.Desc:\n\t\t\t\tsortTokens = append(sortTokens, \"DESC\")\n\t\t\tcase s.Asc:\n\t\t\t\tsortTokens = append(sortTokens, \"ASC\")\n\t\t\t\t// neither set: ASC is the server default; emit nothing.\n\t\t\t}\n\t\t}\n\t\targs = append(args, \"SORTBY\", len(sortTokens))\n\t\targs = append(args, sortTokens...)\n\t}\n\n\t// LIMIT (optional).\n\tif o.Limit != nil {\n\t\targs = append(args, \"LIMIT\", o.Limit.Offset, o.Limit.Count)\n\t}","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/search_collect.go#L98-L134","documentation":"Within a single COLLECT SORTBY field, ASC and DESC are mutually exclusive — a field sorts in one direction only. buildCollectArgs rejects entries with both Asc and Desc set to true rather than emitting an ambiguous SORTBY clause.","triggerScenarios":"A CollectOptions.SortBy entry with both Asc: true and Desc: true; buildCollectArgs returns this error during argument construction.","commonSituations":"Merging two config sources that each set a direction flag; copying a struct and forgetting to clear the old direction; a UI toggle that sets both booleans.","solutions":["Set exactly one of Asc or Desc (or neither, for the server default)","Use a single direction enum/helper instead of two booleans","Clear the opposite flag whenever one is set"],"exampleFix":"// before\nf := redis.CollectSortByField{FieldName: \"@price\", Asc: true, Desc: true}\n// after\nf := redis.CollectSortByField{FieldName: \"@price\", Desc: true}","handlingStrategy":"validation","validationCode":"if s.Asc && s.Desc {\n    return fmt.Errorf(\"ASC and DESC are mutually exclusive for field %s\", s.FieldName)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model direction as an enum (Asc/Desc/None) rather than two booleans","Normalize direction flags in a SortBy-field constructor","Unit-test that Asc and Desc are never both set"],"tags":["search","ft-aggregate","collect","validation"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}