{"record":{"id":"72500f254ea1366d","repo":"redis/go-redis","slug":"to-route-commands-randomly-use-newfailovercluster","errorCode":null,"errorMessage":"to route commands randomly, use NewFailoverClusterClient","messagePattern":"to route commands randomly, use NewFailoverClusterClient","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sentinel.go","lineNumber":552,"sourceCode":"\t}\n\n\treturn o, nil\n}\n\n// NewFailoverClient returns a Redis client that uses Redis Sentinel\n// for automatic failover. It's safe for concurrent use by multiple\n// goroutines.\n// Passing nil FailoverOptions will cause a panic.\nfunc NewFailoverClient(failoverOpt *FailoverOptions) *Client {\n\tif failoverOpt == nil {\n\t\tpanic(\"redis: NewFailoverClient nil options\")\n\t}\n\n\tif failoverOpt.RouteByLatency {\n\t\tpanic(\"to route commands by latency, use NewFailoverClusterClient\")\n\t}\n\tif failoverOpt.RouteRandomly {\n\t\tpanic(\"to route commands randomly, use NewFailoverClusterClient\")\n\t}\n\n\tsentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))\n\tcopy(sentinelAddrs, failoverOpt.SentinelAddrs)\n\n\trand.Shuffle(len(sentinelAddrs), func(i, j int) {\n\t\tsentinelAddrs[i], sentinelAddrs[j] = sentinelAddrs[j], sentinelAddrs[i]\n\t})\n\n\tfailover := &sentinelFailover{\n\t\topt:           failoverOpt,\n\t\tsentinelAddrs: sentinelAddrs,\n\t}\n\n\topt := failoverOpt.clientOptions()\n\topt.Dialer = masterReplicaDialer(failover)\n\topt.init()\n","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/sentinel.go#L534-L570","documentation":"NewFailoverClient rejects FailoverOptions.RouteRandomly=true because random replica routing is only implemented by the cluster client. The sentinel failover client cannot route reads randomly across nodes, so the constructor panics with a pointer to NewFailoverClusterClient.","triggerScenarios":"Calling redis.NewFailoverClient with &redis.FailoverOptions{RouteRandomly: true, ...} set.","commonSituations":"Reusing cluster-style options structs for the sentinel client; toggling routing strategy via config without switching constructor; migrating from ClusterClient back to sentinel while leaving the flag set.","solutions":["Call redis.NewFailoverClusterClient(opts) instead of NewFailoverClient when you need RouteRandomly.","Set RouteRandomly to false (or omit it) if the sentinel client is what you actually want."],"exampleFix":"// before\nclient := redis.NewFailoverClient(&redis.FailoverOptions{\n    MasterName: \"mymaster\",\n    SentinelAddrs: addrs,\n    RouteRandomly: true, // panics\n})\n\n// after\nclient := redis.NewFailoverClusterClient(&redis.FailoverOptions{\n    MasterName: \"mymaster\",\n    SentinelAddrs: addrs,\n    RouteRandomly: true,\n})","handlingStrategy":"validation","validationCode":"if opt.RouteRandomly {\n    return errors.New(\"RouteRandomly requires NewFailoverClusterClient, not NewFailoverClient\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not share one options struct across ClusterClient and failover constructions; explicitly zero routing flags for the sentinel client.","If random replica reads are a requirement, choose NewFailoverClusterClient from the start."],"tags":["panic","sentinel","cluster","routing","misconfiguration"],"backgroundTag":"invalid-option-combination","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}