go-redis/redis · critical
redis: NewFailoverClusterClient nil options
Error message
redis: NewFailoverClusterClient nil options
What it means
NewFailoverClusterClient panics when failoverOpt is nil. Like NewSentinelClient, the function immediately dereferences failoverOpt (reads SentinelAddrs), so the guard converts a latent nil-deref into a clear, explicit panic.
Source
Thrown at sentinel.go:1270
}
addr := net.JoinHostPort(parts[3], parts[4])
c.trySwitchMaster(pubsub.getContext(), addr)
}
if c.onUpdate != nil {
c.onUpdate(ctx)
}
}
}
//------------------------------------------------------------------------------
// NewFailoverClusterClient returns a client that supports routing read-only commands
// to a replica node.
// Passing nil FailoverOptions will cause a panic.
func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient {
if failoverOpt == nil {
panic("redis: NewFailoverClusterClient nil options")
}
sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
copy(sentinelAddrs, failoverOpt.SentinelAddrs)
failover := &sentinelFailover{
opt: failoverOpt,
sentinelAddrs: sentinelAddrs,
}
opt := failoverOpt.clusterOptions()
if failoverOpt.DB != 0 {
onConnect := opt.OnConnect
opt.OnConnect = func(ctx context.Context, cn *Conn) error {
if err := cn.Select(ctx, failoverOpt.DB).Err(); err != nil {
return err
}View on GitHub (pinned to 36d97525cd)
Solutions
- Construct and pass a non-nil *redis.FailoverOptions with MasterName and SentinelAddrs.
- Handle config-load errors explicitly instead of letting a nil pointer reach the constructor.
- Add a guard at the call site that returns a descriptive error when options are missing.
Example fix
// before
var fo *redis.FailoverOptions
c := redis.NewFailoverClusterClient(fo)
// after
c := redis.NewFailoverClusterClient(&redis.FailoverOptions{
MasterName: "mymaster",
SentinelAddrs: []string{"sentinel:26379"},
}) Defensive patterns
Strategy: validation
Validate before calling
func buildFailoverCluster(fo *redis.FailoverOptions) (*redis.ClusterClient, error) {
if fo == nil {
return nil, errors.New("redis.FailoverOptions must not be nil")
}
return redis.NewFailoverClusterClient(fo), nil
} Type guard
func isNonNilFailoverOptions(fo *redis.FailoverOptions) bool { return fo != nil } Prevention
- Always construct *redis.FailoverOptions with &redis.FailoverOptions{...} and set MasterName + SentinelAddrs.
- Return (Options, error) from config loaders so nil never propagates.
- Add a nil guard at the call site returning a descriptive error.
When it happens
Trigger: Calling redis.NewFailoverClusterClient(nil), or passing a *redis.FailoverOptions that was conditionally constructed and left nil.
Common situations: Config-builder function returning nil on a parse error that the caller ignored, or a refactor that removed the options assignment.
Related errors
- redis: NewSentinelClient nil options
- redis: NewClusterClient nil options
- redis: Watch requires all keys to be in the same slot
- redis: no sentinels configured
- redis: all sentinels specified in configuration are unreacha
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/0ce17bca4ce4a552.json.
Report an issue: GitHub.