redis/go-redis · error
to route commands by latency, use NewFailoverClusterClient
Error message
to route commands by latency, use NewFailoverClusterClient
What it means
NewFailoverClient rejects FailoverOptions.RouteByLatency=true because read-by-latency routing is only implemented by the cluster client. The sentinel failover client has no latency-based replica routing, so the constructor panics to point the developer at the correct constructor.
Source
Thrown at sentinel.go:549
// any parameters left?
if r := q.remaining(); len(r) > 0 {
return nil, fmt.Errorf("redis: unexpected option: %s", strings.Join(r, ", "))
}
return o, nil
}
// NewFailoverClient returns a Redis client that uses Redis Sentinel
// for automatic failover. It's safe for concurrent use by multiple
// goroutines.
// Passing nil FailoverOptions will cause a panic.
func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
if failoverOpt == nil {
panic("redis: NewFailoverClient nil options")
}
if failoverOpt.RouteByLatency {
panic("to route commands by latency, use NewFailoverClusterClient")
}
if failoverOpt.RouteRandomly {
panic("to route commands randomly, use NewFailoverClusterClient")
}
sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
copy(sentinelAddrs, failoverOpt.SentinelAddrs)
rand.Shuffle(len(sentinelAddrs), func(i, j int) {
sentinelAddrs[i], sentinelAddrs[j] = sentinelAddrs[j], sentinelAddrs[i]
})
failover := &sentinelFailover{
opt: failoverOpt,
sentinelAddrs: sentinelAddrs,
}
opt := failoverOpt.clientOptions()View on GitHub (pinned to c5cad058c7)
Solutions
- Call redis.NewFailoverClusterClient(opts) instead of NewFailoverClient when you need RouteByLatency.
- Set RouteByLatency to false (or omit it) if the sentinel client is what you actually want.
Example fix
// before
client := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: addrs,
RouteByLatency: true, // panics
})
// after
client := redis.NewFailoverClusterClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: addrs,
RouteByLatency: true,
}) Defensive patterns
Strategy: validation
Validate before calling
if opt.RouteByLatency {
return errors.New("RouteByLatency requires NewFailoverClusterClient, not NewFailoverClient")
} Prevention
- Keep separate config structs for cluster and sentinel clients so routing flags cannot leak between them.
- When migrating between client types, audit boolean routing flags (RouteByLatency, RouteRandomly) before changing the constructor.
When it happens
Trigger: Calling redis.NewFailoverClient with &redis.FailoverOptions{RouteByLatency: true, ...} set.
Common situations: Copy-pasting options from a ClusterClient configuration (where RouteByLatency is valid) into FailoverOptions; sharing a single options struct across multiple client types in a config layer.
Related errors
- to route commands randomly, use NewFailoverClusterClient
- redis: NewFailoverClusterClient nil options
- redis: failed to create connection pool: %w
- redis: failed to create pubsub pool: %w
- redis: NewFailoverClient nil options
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/0202334d381550c7.
Report an issue: GitHub.