{"record":{"id":"dfb343fa23c1a1fc","repo":"redis/go-redis","slug":"ft-search-asc-and-desc-are-mutually-exclusive","errorCode":null,"errorMessage":"FT.SEARCH: ASC and DESC are mutually exclusive","messagePattern":"FT\\.SEARCH: ASC and DESC are mutually exclusive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"search_commands.go","lineNumber":3403,"sourceCode":"\t\t}\n\t\tif options.Expander != \"\" {\n\t\t\tqueryArgs = append(queryArgs, \"EXPANDER\", options.Expander)\n\t\t}\n\t\tif options.Scorer != \"\" {\n\t\t\tqueryArgs = append(queryArgs, \"SCORER\", options.Scorer)\n\t\t}\n\t\tif options.ExplainScore {\n\t\t\tqueryArgs = append(queryArgs, \"EXPLAINSCORE\")\n\t\t}\n\t\tif options.Payload != \"\" {\n\t\t\tqueryArgs = append(queryArgs, \"PAYLOAD\", options.Payload)\n\t\t}\n\t\tif options.SortBy != nil {\n\t\t\tqueryArgs = append(queryArgs, \"SORTBY\")\n\t\t\tfor _, sortBy := range options.SortBy {\n\t\t\t\tqueryArgs = append(queryArgs, sortBy.FieldName)\n\t\t\t\tif sortBy.Asc && sortBy.Desc {\n\t\t\t\t\treturn nil, fmt.Errorf(\"FT.SEARCH: ASC and DESC are mutually exclusive\")\n\t\t\t\t}\n\t\t\t\tif sortBy.Asc {\n\t\t\t\t\tqueryArgs = append(queryArgs, \"ASC\")\n\t\t\t\t}\n\t\t\t\tif sortBy.Desc {\n\t\t\t\t\tqueryArgs = append(queryArgs, \"DESC\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tif options.SortByWithCount {\n\t\t\t\tqueryArgs = append(queryArgs, \"WITHCOUNT\")\n\t\t\t}\n\t\t}\n\t\tif options.LimitOffset >= 0 && options.Limit > 0 {\n\t\t\tqueryArgs = append(queryArgs, \"LIMIT\", options.LimitOffset, options.Limit)\n\t\t}\n\t\tif options.Params != nil {\n\t\t\tqueryArgs = append(queryArgs, \"PARAMS\", len(options.Params)*2)\n\t\t\tfor key, value := range options.Params {","sourceCodeStart":3385,"sourceCodeEnd":3421,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/search_commands.go#L3385-L3421","documentation":"go-redis validates FTSearchOptions before sending FT.SEARCH: within a single SortBy entry, Asc and Desc cannot both be true since they are mutually exclusive sort directions. This is a client-side argument-validation error raised while building the command arguments, before anything reaches the server.","triggerScenarios":"Calling FTSearch (or FTSearchWithArgs) with options.SortBy where one SearchSortBy has both Asc: true and Desc: true set.","commonSituations":"Copy-paste or programmatic construction of sort options where both flags are set from separate booleans; merging user-supplied options without clearing the opposite flag; misunderstanding that the zero value (neither set) is the default ASC.","solutions":["Set only one direction flag per SortBy entry: Asc: true or Desc: true, not both","Leave both false to use the server default (ASC) when no explicit direction is needed","If options come from user input or config, sanitize them: if both are set, prefer one (e.g. Desc) or reject the input earlier","Review option-merging code so setting one flag resets the other"],"exampleFix":"// before\nsortBy := redis.SearchSortBy{FieldName: \"age\", Asc: true, Desc: true}\n// after\nsortBy := redis.SearchSortBy{FieldName: \"age\", Desc: true}","handlingStrategy":"validation","validationCode":"func sanitizeSortBy(sortBy []redis.SearchSortBy) []redis.SearchSortBy {\n    out := make([]redis.SearchSortBy, len(sortBy))\n    for i, s := range sortBy {\n        if s.Asc && s.Desc { s.Desc = false } // or reject\n        out[i] = s\n    }\n    return out\n}","typeGuard":"func sortDirectionValid(s redis.SearchSortBy) bool {\n    return !(s.Asc && s.Desc)\n}","tryCatchPattern":"args, err := redis.NewFTSearchQuery(\"idx\", query, opts).Args() // or call FTSearch\nif err != nil {\n    if strings.Contains(err.Error(), \"mutually exclusive\") {\n        return fmt.Errorf(\"bad sort config: %w\", err)\n    }\n    return err\n}","preventionTips":["Never set both Asc and Desc; treat them as an enum in your app layer","Sanitize merged/user-supplied options before building queries","Add a unit test asserting at most one direction flag per SortBy entry"],"tags":["redis","search","validation","query-options"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}