go-redis/redis · critical

redis: NewFailoverClusterClient nil options

Error message

redis: NewFailoverClusterClient nil options

What it means

NewFailoverClusterClient panics when failoverOpt is nil. Like NewSentinelClient, the function immediately dereferences failoverOpt (reads SentinelAddrs), so the guard converts a latent nil-deref into a clear, explicit panic.

Source

Thrown at sentinel.go:1270

			}
			addr := net.JoinHostPort(parts[3], parts[4])
			c.trySwitchMaster(pubsub.getContext(), addr)
		}

		if c.onUpdate != nil {
			c.onUpdate(ctx)
		}
	}
}

//------------------------------------------------------------------------------

// NewFailoverClusterClient returns a client that supports routing read-only commands
// to a replica node.
// Passing nil FailoverOptions will cause a panic.
func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient {
	if failoverOpt == nil {
		panic("redis: NewFailoverClusterClient nil options")
	}

	sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
	copy(sentinelAddrs, failoverOpt.SentinelAddrs)

	failover := &sentinelFailover{
		opt:           failoverOpt,
		sentinelAddrs: sentinelAddrs,
	}

	opt := failoverOpt.clusterOptions()
	if failoverOpt.DB != 0 {
		onConnect := opt.OnConnect

		opt.OnConnect = func(ctx context.Context, cn *Conn) error {
			if err := cn.Select(ctx, failoverOpt.DB).Err(); err != nil {
				return err
			}

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Construct and pass a non-nil *redis.FailoverOptions with MasterName and SentinelAddrs.
  2. Handle config-load errors explicitly instead of letting a nil pointer reach the constructor.
  3. Add a guard at the call site that returns a descriptive error when options are missing.

Example fix

// before
var fo *redis.FailoverOptions
c := redis.NewFailoverClusterClient(fo)

// after
c := redis.NewFailoverClusterClient(&redis.FailoverOptions{
    MasterName:   "mymaster",
    SentinelAddrs: []string{"sentinel:26379"},
})
Defensive patterns

Strategy: validation

Validate before calling

func buildFailoverCluster(fo *redis.FailoverOptions) (*redis.ClusterClient, error) {
    if fo == nil {
        return nil, errors.New("redis.FailoverOptions must not be nil")
    }
    return redis.NewFailoverClusterClient(fo), nil
}

Type guard

func isNonNilFailoverOptions(fo *redis.FailoverOptions) bool { return fo != nil }

Prevention

When it happens

Trigger: Calling redis.NewFailoverClusterClient(nil), or passing a *redis.FailoverOptions that was conditionally constructed and left nil.

Common situations: Config-builder function returning nil on a parse error that the caller ignored, or a refactor that removed the options assignment.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/0ce17bca4ce4a552.json. Report an issue: GitHub.