redis/go-redis · critical
redis: NewUniversalClient nil options
Error message
redis: NewUniversalClient nil options
What it means
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.
Source
Thrown at universal.go:448
// 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 c5cad058c7)
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.
Example fix
// before
var opts *redis.UniversalOptions
client := redis.NewUniversalClient(opts) // panics
// after
client := redis.NewUniversalClient(&redis.UniversalOptions{
Addrs: []string{"localhost:6379"},
}) Defensive patterns
Strategy: validation
Validate before calling
func validateUniversalOptions(opts *redis.UniversalOptions) error {
if opts == nil {
return errors.New("universal options must not be nil")
}
if opts.MasterName == "" && len(opts.Addrs) == 0 {
return errors.New("either Addrs or MasterName+SentinelAddrs are required")
}
return nil
} Type guard
func hasUniversalOptions(opts *redis.UniversalOptions) bool { return opts != nil } Try / catch
// Last-resort recover wrapper:
func safeNewUniversalClient(opts *redis.UniversalOptions) (c redis.UniversalClient, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("NewUniversalClient: %v", r)
}
}()
return redis.NewUniversalClient(opts), nil
} Prevention
- 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.
When it happens
Trigger: Calling redis.NewUniversalClient(nil); passing a *UniversalOptions obtained from a config loader that returned nil when no redis section was present.
Common situations: 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.
Related errors
- redis: NewFailoverClient nil options
- redis: NewSentinelClient nil options
- redis: NewFailoverClusterClient nil options
- both LibName and LibVer cannot be set at the same time
- at least one of LibName and LibVer should be set
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/55b6090a54549147.
Report an issue: GitHub.