go-redis/redis · critical
redis: NewUniversalClient nil options
Error message
redis: NewUniversalClient nil options
What it means
NewUniversalClient panics with 'redis: NewUniversalClient nil options' when the supplied *UniversalOptions is nil (universal.go:421-424). The universal client branches on fields of opts (MasterName, Addrs, IsClusterMode, etc.) to decide whether to build a Failover, Cluster, Ring, or simple Client; a nil pointer has no fields to inspect, so the constructor documents and enforces non-nil with a panic at startup.
Source
Thrown at universal.go:423
// delegate to the underlying client.
_ UniversalClient = (*AutoPipeliner)(nil)
)
// NewUniversalClient returns a new multi client. The type of the returned client depends
// on the following conditions:
//
// 1. If the MasterName option is specified with RouteByLatency, RouteRandomly or IsClusterMode,
// a FailoverClusterClient is returned.
// 2. If the MasterName option is specified without RouteByLatency, RouteRandomly or IsClusterMode,
// a sentinel-backed FailoverClient is returned.
// 3. If the number of Addrs is two or more, or IsClusterMode option is specified,
// a ClusterClient is returned.
// 4. Otherwise, a single-node Client is returned.
//
// Passing nil UniversalOptions will cause a panic.
func NewUniversalClient(opts *UniversalOptions) UniversalClient {
if opts == nil {
panic("redis: NewUniversalClient nil options")
}
switch {
case opts.MasterName != "" && (opts.RouteByLatency || opts.RouteRandomly || opts.IsClusterMode):
return NewFailoverClusterClient(opts.Failover())
case opts.MasterName != "":
return NewFailoverClient(opts.Failover())
case len(opts.Addrs) > 1 || opts.IsClusterMode:
return NewClusterClient(opts.Cluster())
default:
return NewClient(opts.Simple())
}
}
View on GitHub (pinned to 36d97525cd)
Solutions
- Always pass a non-nil *redis.UniversalOptions, at minimum &redis.UniversalOptions{Addrs: []string{"localhost:6379"}}.
- Make your options loader return a valid *UniversalOptions with defaults rather than nil; validate config and fail with a clear error if Addrs is empty.
- Guard the call site: if opts == nil { opts = &redis.UniversalOptions{Addrs: defaultAddrs} } or return an error from your factory.
- Wrap NewUniversalClient in a constructor that validates inputs and returns an error instead of letting the library panic.
Example fix
// before
client := redis.NewUniversalClient(loadUniversalCfg()) // returns nil
// after
opts := loadUniversalCfg()
if opts == nil {
opts = &redis.UniversalOptions{Addrs: []string{"localhost:6379"}}
}
client := redis.NewUniversalClient(opts) Defensive patterns
Strategy: validation
Validate before calling
func newUniversalClient(opts *redis.UniversalOptions) (redis.UniversalClient, error) {
if opts == nil {
return nil, errors.New("universal options must not be nil")
}
if len(opts.Addrs) == 0 && opts.MasterName == "" {
return nil, errors.New("universal options require Addrs or MasterName")
}
return redis.NewUniversalClient(opts), nil
} Type guard
func validUniversalOptions(opts *redis.UniversalOptions) bool {
return opts != nil && (len(opts.Addrs) > 0 || opts.MasterName != "")
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Fatalf("universal client init failed: %v", r)
}
}()
client := redis.NewUniversalClient(opts) Prevention
- Always pass &redis.UniversalOptions{Addrs: []string{...}} or set MasterName for sentinel.
- Have your config loader return a non-nil *UniversalOptions with defaults.
- Wrap NewUniversalClient in a factory that validates Addrs/MasterName and returns an error.
- Unit-test the config builder to assert non-nil and non-empty routing fields.
When it happens
Trigger: Calling redis.NewUniversalClient(nil); passing a *UniversalOptions variable that was declared but never assigned; a config loader that returns nil UniversalOptions on an unhandled branch; conditional client setup that leaves opts nil in some path.
Common situations: Universal config sourced from env/YAML where no fields were set so the builder returns nil; client-type selection logic that reaches NewUniversalClient with an unpopulated options pointer; refactors that extract construction behind a helper returning nil on the empty case; tests that omit the options argument.
Related errors
- redis: NewClient nil options
- redis: NewRing nil options
- redis: NewSentinelClient nil options
- redis: NewFailoverClusterClient nil options
- redis: NewClusterClient nil options
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/1fd82987226a4782.json.
Report an issue: GitHub.