{"record":{"id":"fb3529c156a076d2","repo":"redis/go-redis","slug":"redis-newfailoverclusterclient-nil-options","errorCode":null,"errorMessage":"redis: NewFailoverClusterClient nil options","messagePattern":"redis: NewFailoverClusterClient nil options","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"sentinel.go","lineNumber":1263,"sourceCode":"\t\t\t}\n\t\t\taddr := net.JoinHostPort(parts[3], parts[4])\n\t\t\tc.trySwitchMaster(pubsub.getContext(), addr)\n\t\t}\n\n\t\tif c.onUpdate != nil {\n\t\t\tc.onUpdate(ctx)\n\t\t}\n\t}\n}\n\n//------------------------------------------------------------------------------\n\n// NewFailoverClusterClient returns a client that supports routing read-only commands\n// to a replica node.\n// Passing nil FailoverOptions will cause a panic.\nfunc NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient {\n\tif failoverOpt == nil {\n\t\tpanic(\"redis: NewFailoverClusterClient nil options\")\n\t}\n\n\tsentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))\n\tcopy(sentinelAddrs, failoverOpt.SentinelAddrs)\n\n\tfailover := &sentinelFailover{\n\t\topt:           failoverOpt,\n\t\tsentinelAddrs: sentinelAddrs,\n\t}\n\n\topt := failoverOpt.clusterOptions()\n\tif failoverOpt.DB != 0 {\n\t\tonConnect := opt.OnConnect\n\n\t\topt.OnConnect = func(ctx context.Context, cn *Conn) error {\n\t\t\tif err := cn.Select(ctx, failoverOpt.DB).Err(); err != nil {\n\t\t\t\treturn err\n\t\t\t}","sourceCodeStart":1245,"sourceCodeEnd":1281,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/sentinel.go#L1245-L1281","documentation":"NewFailoverClusterClient panics when the *FailoverOptions argument is nil. The constructor copies SentinelAddrs and builds a sentinelFailover from the options immediately, so a nil pointer is rejected up front with an explicit panic.","triggerScenarios":"Calling redis.NewFailoverClusterClient(nil), or with an uninitialized *FailoverOptions. Also reachable via NewUniversalClient when opts.MasterName != \"\" and RouteByLatency/RouteRandomly/IsClusterMode are set, if UniversalOptions were hand-built with nil Failover fields and MasterName set.","commonSituations":"Config-driven client factories that select failover-cluster mode but skip options population; a nil FailoverOptions field inside UniversalOptions combined with a non-empty MasterName; test helpers that only partially populate options.","solutions":["Provide a populated &redis.FailoverOptions{MasterName: ..., SentinelAddrs: [...]}.","Nil-check the options before calling NewFailoverClusterClient.","If using NewUniversalClient, ensure opts.Failover() (populated UniversalOptions fields) yields non-nil FailoverOptions; leave MasterName empty if not using sentinel."],"exampleFix":"// before\nvar opt *redis.FailoverOptions\nclient := redis.NewFailoverClusterClient(opt) // panics\n\n// after\nclient := redis.NewFailoverClusterClient(&redis.FailoverOptions{\n    MasterName:    \"mymaster\",\n    SentinelAddrs: []string{\":26379\"},\n})","handlingStrategy":"validation","validationCode":"func validateFailoverClusterOptions(opt *redis.FailoverOptions) error {\n    if opt == nil {\n        return errors.New(\"failover cluster options must not be nil\")\n    }\n    if opt.MasterName == \"\" || len(opt.SentinelAddrs) == 0 {\n        return errors.New(\"MasterName and SentinelAddrs are required\")\n    }\n    return nil\n}","typeGuard":"func hasFailoverClusterOptions(opt *redis.FailoverOptions) bool { return opt != nil }","tryCatchPattern":"// Last-resort recover wrapper:\nfunc safeNewFailoverClusterClient(opt *redis.FailoverOptions) (c *redis.ClusterClient, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"NewFailoverClusterClient: %v\", r)\n        }\n    }()\n    return redis.NewFailoverClusterClient(opt), nil\n}","preventionTips":["When using NewUniversalClient with MasterName set, make sure the Failover fields of UniversalOptions are populated so opts.Failover() is non-nil.","Validate sentinel config in your config-loading layer before any client construction."],"tags":["panic","nil-options","sentinel","cluster","configuration"],"backgroundTag":"nil-options-panic","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}