{"record":{"id":"c043c73718f343a2","repo":"redis/go-redis","slug":"ft-hybrid-asc-and-desc-are-mutually-exclusive","errorCode":null,"errorMessage":"FT.HYBRID: ASC and DESC are mutually exclusive","messagePattern":"FT\\.HYBRID: ASC and DESC are mutually exclusive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"search_commands.go","lineNumber":4001,"sourceCode":"\t\t\tif options.GroupBy.ReduceFunc != \"\" {\n\t\t\t\targs = append(args, \"REDUCE\", options.GroupBy.ReduceFunc, options.GroupBy.ReduceCount)\n\t\t\t\targs = append(args, options.GroupBy.ReduceParams...)\n\t\t\t}\n\t\t}\n\n\t\t// Add APPLY transformations\n\t\tfor _, apply := range options.Apply {\n\t\t\targs = append(args, \"APPLY\", apply.Expression, \"AS\", apply.AsField)\n\t\t}\n\n\t\t// Add SORTBY\n\t\tif len(options.SortBy) > 0 {\n\t\t\tsortByOptions := []interface{}{}\n\t\t\tfor _, sortBy := range options.SortBy {\n\t\t\t\tsortByOptions = append(sortByOptions, sortBy.FieldName)\n\t\t\t\tif sortBy.Asc && sortBy.Desc {\n\t\t\t\t\tcmd := newFTHybridCmd(ctx, options, args...)\n\t\t\t\t\tcmd.SetErr(fmt.Errorf(\"FT.HYBRID: ASC and DESC are mutually exclusive\"))\n\t\t\t\t\treturn cmd\n\t\t\t\t}\n\t\t\t\tif sortBy.Asc {\n\t\t\t\t\tsortByOptions = append(sortByOptions, \"ASC\")\n\t\t\t\t}\n\t\t\t\tif sortBy.Desc {\n\t\t\t\t\tsortByOptions = append(sortByOptions, \"DESC\")\n\t\t\t\t}\n\t\t\t}\n\t\t\targs = append(args, \"SORTBY\", len(sortByOptions))\n\t\t\targs = append(args, sortByOptions...)\n\t\t}\n\n\t\t// Add FILTER (post-filter)\n\t\tif options.Filter != \"\" {\n\t\t\targs = append(args, \"FILTER\", options.Filter)\n\t\t}\n","sourceCodeStart":3983,"sourceCodeEnd":4019,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/search_commands.go#L3983-L4019","documentation":"FT.HYBRID SORTBY validation error raised client-side. Within a single SortBy entry, Asc and Desc are boolean flags for sort direction; setting both simultaneously is contradictory, so go-redis rejects the options before issuing the command. Exactly one direction (or neither, which defaults to server behavior) must be set.","triggerScenarios":"Passing an FTHybridSortBy entry where both Asc: true and Desc: true are set for the same FieldName.","commonSituations":"Loading sort configuration from a struct or config file where both direction booleans are populated, or merging user-supplied sort options where defaults set Asc=true and user input sets Desc=true.","solutions":["Set only one of Asc or Desc to true for each SortBy entry","Derive the direction from a single source: Asc: dir == \"asc\", Desc: dir == \"desc\" so only one can be true","Normalize options after deserialization: if both are set, reset one to false"],"exampleFix":"// before\nsortBy: FTHybridSortBy{FieldName: \"score\", Asc: true, Desc: true}\n// after\nsortBy: FTHybridSortBy{FieldName: \"score\", Desc: true}","handlingStrategy":"validation","validationCode":"for _, s := range opts.SortBy {\n    if s.Asc && s.Desc { return fmt.Errorf(\"SortBy %q has both Asc and Desc\", s.FieldName) }\n}","typeGuard":null,"tryCatchPattern":"cmd := rdb.FTHybrid(ctx, opts, args...)\nif err := cmd.Err(); err != nil {\n    if strings.Contains(err.Error(), \"mutually exclusive\") { /* normalize sort flags and retry */ }\n    return err\n}","preventionTips":["Represent sort direction as a single enum/flag, not two booleans","Normalize flags right after deserializing user/config input","Default to one direction explicitly"],"tags":["redis","search","ft-hybrid","parameter-validation"],"backgroundTag":"conflicting-options","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}