{"record":{"id":"55b6090a54549147","repo":"redis/go-redis","slug":"redis-newuniversalclient-nil-options","errorCode":null,"errorMessage":"redis: NewUniversalClient nil options","messagePattern":"redis: NewUniversalClient nil options","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"universal.go","lineNumber":448,"sourceCode":"\t// delegate to the underlying client.\n\t_ UniversalClient = (*AutoPipeliner)(nil)\n)\n\n// NewUniversalClient returns a new multi client. The type of the returned client depends\n// on the following conditions:\n//\n//  1. If the MasterName option is specified with RouteByLatency, RouteRandomly or IsClusterMode,\n//     a FailoverClusterClient is returned.\n//  2. If the MasterName option is specified without RouteByLatency, RouteRandomly or IsClusterMode,\n//     a sentinel-backed FailoverClient is returned.\n//  3. If the number of Addrs is two or more, or IsClusterMode option is specified,\n//     a ClusterClient is returned.\n//  4. Otherwise, a single-node Client is returned.\n//\n// Passing nil UniversalOptions will cause a panic.\nfunc NewUniversalClient(opts *UniversalOptions) UniversalClient {\n\tif opts == nil {\n\t\tpanic(\"redis: NewUniversalClient nil options\")\n\t}\n\n\tswitch {\n\tcase opts.MasterName != \"\" && (opts.RouteByLatency || opts.RouteRandomly || opts.IsClusterMode):\n\t\treturn NewFailoverClusterClient(opts.Failover())\n\tcase opts.MasterName != \"\":\n\t\treturn NewFailoverClient(opts.Failover())\n\tcase len(opts.Addrs) > 1 || opts.IsClusterMode:\n\t\treturn NewClusterClient(opts.Cluster())\n\tdefault:\n\t\treturn NewClient(opts.Simple())\n\t}\n}\n","sourceCodeStart":430,"sourceCodeEnd":462,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/universal.go#L430-L462","documentation":"NewUniversalClient panics when the *UniversalOptions argument is nil. UniversalOptions drives which concrete client (failover-cluster, failover, cluster, or single-node) is built, and the constructor reads its fields immediately, so nil is rejected with a panic as documented on the function.","triggerScenarios":"Calling redis.NewUniversalClient(nil); passing a *UniversalOptions obtained from a config loader that returned nil when no redis section was present.","commonSituations":"Generic client factories in application frameworks that forward a nil options struct when configuration is absent or failed to parse; struct-typed config parsed from YAML/env left as nil pointer when unset.","solutions":["Construct a &redis.UniversalOptions{Addrs: []string{\"host:6379\"}} (or with MasterName/SentinelAddrs for failover) before calling NewUniversalClient.","Add a nil guard in the factory that builds the client, returning a configuration error instead of invoking the constructor.","Ensure your config unmarshaling allocates the UniversalOptions struct (value type, not nil pointer) even when fields are empty."],"exampleFix":"// before\nvar opts *redis.UniversalOptions\nclient := redis.NewUniversalClient(opts) // panics\n\n// after\nclient := redis.NewUniversalClient(&redis.UniversalOptions{\n    Addrs: []string{\"localhost:6379\"},\n})","handlingStrategy":"validation","validationCode":"func validateUniversalOptions(opts *redis.UniversalOptions) error {\n    if opts == nil {\n        return errors.New(\"universal options must not be nil\")\n    }\n    if opts.MasterName == \"\" && len(opts.Addrs) == 0 {\n        return errors.New(\"either Addrs or MasterName+SentinelAddrs are required\")\n    }\n    return nil\n}","typeGuard":"func hasUniversalOptions(opts *redis.UniversalOptions) bool { return opts != nil }","tryCatchPattern":"// Last-resort recover wrapper:\nfunc safeNewUniversalClient(opts *redis.UniversalOptions) (c redis.UniversalClient, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"NewUniversalClient: %v\", r)\n        }\n    }()\n    return redis.NewUniversalClient(opts), nil\n}","preventionTips":["Return a configuration error from your settings loader instead of a nil *UniversalOptions when the redis section is missing.","Unmarshal config into a value (non-pointer) struct so an empty section yields a zero-value options object, not nil.","Wrap NewUniversalClient in one shared factory that nil-checks before constructing."],"tags":["panic","nil-options","universal-client","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"}