go-redis/redis · critical
redis: NewClusterClient nil options
Error message
redis: NewClusterClient nil options
What it means
NewClusterClient panics when opt is nil. The constructor immediately calls opt.init() and reads opt fields, so the guard converts a guaranteed nil-pointer dereference into an explicit, descriptive panic.
Source
Thrown at osscluster.go:1193
// himport is the cluster-wide HIMPORT fieldset registry, shared with
// every node client (masters and replicas alike — roles change with the
// topology) so any connection serving an HIMPORT SET can lazily replay
// the PREPARE (see himport.go, himport_cluster.go).
himport *himportRegistry
autopipelinerMu *sync.Mutex // guards the autopipeliner fields against concurrent first-call creation
autopipeliner *AutoPipeliner // blocking face (ClusterClient.AutoPipeline)
asyncAutopipeliner *AutoPipeliner // deferred face (ClusterClient.AsyncAutoPipeline)
autopipelinerClosed bool // set by Close: refuse to resurrect a pipeliner on a closed client
}
// NewClusterClient returns a Redis Cluster client as described in
// https://redis.io/docs/latest/operate/oss_and_stack/reference/cluster-spec.
// Passing nil ClusterOptions will cause a panic.
func NewClusterClient(opt *ClusterOptions) *ClusterClient {
if opt == nil {
panic("redis: NewClusterClient nil options")
}
opt.init()
c := &ClusterClient{
opt: opt,
nodes: newClusterNodes(opt),
himport: newHImportRegistry(),
autopipelinerMu: &sync.Mutex{},
}
// Every node client shares the cluster-wide fieldset registry, replicas
// included: a promoted replica's connections carry no prepared flags, so
// the first HIMPORT SET routed to it replays the PREPARE lazily.
c.nodes.OnNewNode(func(nodeClient *Client) {
nodeClient.himport = c.himport
})
c.cmdsInfoCache = newCmdsInfoCache(c.cmdsInfo)View on GitHub (pinned to 36d97525cd)
Solutions
- Pass a non-nil *redis.ClusterOptions with at least Addrs populated.
- Handle config-load errors explicitly rather than propagating nil.
- Add a nil check at the call site returning a descriptive error.
Example fix
// before
var opt *redis.ClusterOptions
c := redis.NewClusterClient(opt)
// after
c := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{":7000", ":7001", ":7002"},
}) Defensive patterns
Strategy: validation
Validate before calling
func buildClusterClient(opt *redis.ClusterOptions) (*redis.ClusterClient, error) {
if opt == nil {
return nil, errors.New("redis.ClusterOptions must not be nil")
}
return redis.NewClusterClient(opt), nil
} Type guard
func isNonNilClusterOptions(opt *redis.ClusterOptions) bool { return opt != nil } Prevention
- Always construct *redis.ClusterOptions with &redis.ClusterOptions{Addrs: ...} inline.
- Return (ClusterOptions, error) from config loaders to avoid nil propagation.
- Add a nil guard at the call site.
When it happens
Trigger: Calling redis.NewClusterClient(nil), or passing a *redis.ClusterOptions variable that was never assigned (var opt *redis.ClusterOptions; NewClusterClient(opt)).
Common situations: Config-loader returning nil on error and the caller ignoring it, or a refactor dropping the options construction.
Related errors
- redis: NewFailoverClusterClient nil options
- redis: NewSentinelClient nil options
- redis: Watch requires all keys to be in the same slot
- redis: NewClient nil options
- redis: NewRing nil options
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/abd93580a7c68007.json.
Report an issue: GitHub.