redis/go-redis · critical
redis: NewFailoverClient nil options
Error message
redis: NewFailoverClient nil options
What it means
NewFailoverClient panics immediately when the *FailoverOptions argument is nil. The constructor requires a non-nil options struct because it reads SentinelAddrs, MasterName and other fields directly to build the client. The library deliberately fails fast instead of returning a half-configured client.
Source
Thrown at sentinel.go:545
if o.TLSConfig != nil && q.has("skip_verify") {
o.TLSConfig.InsecureSkipVerify = q.bool("skip_verify")
}
// 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,View on GitHub (pinned to c5cad058c7)
Solutions
- Construct a valid &redis.FailoverOptions{...} with at least MasterName and SentinelAddrs set before calling NewFailoverClient.
- Add a nil check (or a config loader that never returns nil) before invoking NewFailoverClient.
- If sentinel failover is not actually needed, use redis.NewClient(&redis.Options{...}) instead.
Example fix
// before
var opt *redis.FailoverOptions
client := redis.NewFailoverClient(opt) // panics
// after
opt := &redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{":26379", ":26380"},
}
client := redis.NewFailoverClient(opt) Defensive patterns
Strategy: validation
Validate before calling
func validateFailoverOptions(opt *redis.FailoverOptions) error {
if opt == nil {
return errors.New("failover options must not be nil")
}
if opt.MasterName == "" || len(opt.SentinelAddrs) == 0 {
return errors.New("MasterName and SentinelAddrs are required")
}
if opt.RouteByLatency || opt.RouteRandomly {
return errors.New("use NewFailoverClusterClient for routing options")
}
return nil
} Type guard
func hasFailoverOptions(opt *redis.FailoverOptions) bool { return opt != nil } Try / catch
// Go panics are not catchable via try/catch; recover only as a last resort:
func safeNewFailoverClient(opt *redis.FailoverOptions) (c *redis.Client, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("NewFailoverClient: %v", r)
}
}()
return redis.NewFailoverClient(opt), nil
} Prevention
- Always build FailoverOptions as a struct literal at the call site rather than reusing a possibly-nil pointer.
- Centralize client construction in one factory that validates options first.
- Load sentinel settings from config with explicit 'missing' errors instead of returning nil.
When it happens
Trigger: Calling redis.NewFailoverClient(nil), or calling it with a *FailoverOptions variable that was declared but never assigned (nil pointer).
Common situations: Building options conditionally in a helper that returns *FailoverOptions and returning nil on a config-parse failure; loading options from env/flags where the failover section is missing; passing a nil pointer through a factory or NewUniversalClient path that forwards opts.Failover() results.
Related errors
- redis: NewSentinelClient nil options
- redis: NewFailoverClusterClient nil options
- redis: NewUniversalClient nil options
- redis: failed to create connection pool: %w
- redis: failed to create pubsub pool: %w
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/1cfcd90d79ef08f8.
Report an issue: GitHub.