redis/go-redis · error

to route commands randomly, use NewFailoverClusterClient

Error message

to route commands randomly, use NewFailoverClusterClient

What it means

NewFailoverClient rejects FailoverOptions.RouteRandomly=true because random replica routing is only implemented by the cluster client. The sentinel failover client cannot route reads randomly across nodes, so the constructor panics with a pointer to NewFailoverClusterClient.

Source

Thrown at sentinel.go:552

	}

	return o, nil
}

// NewFailoverClient returns a Redis client that uses Redis Sentinel
// for automatic failover. It's safe for concurrent use by multiple
// goroutines.
// Passing nil FailoverOptions will cause a panic.
func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
	if failoverOpt == nil {
		panic("redis: NewFailoverClient nil options")
	}

	if failoverOpt.RouteByLatency {
		panic("to route commands by latency, use NewFailoverClusterClient")
	}
	if failoverOpt.RouteRandomly {
		panic("to route commands randomly, use NewFailoverClusterClient")
	}

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

	rand.Shuffle(len(sentinelAddrs), func(i, j int) {
		sentinelAddrs[i], sentinelAddrs[j] = sentinelAddrs[j], sentinelAddrs[i]
	})

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

	opt := failoverOpt.clientOptions()
	opt.Dialer = masterReplicaDialer(failover)
	opt.init()

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Call redis.NewFailoverClusterClient(opts) instead of NewFailoverClient when you need RouteRandomly.
  2. Set RouteRandomly to false (or omit it) if the sentinel client is what you actually want.

Example fix

// before
client := redis.NewFailoverClient(&redis.FailoverOptions{
    MasterName: "mymaster",
    SentinelAddrs: addrs,
    RouteRandomly: true, // panics
})

// after
client := redis.NewFailoverClusterClient(&redis.FailoverOptions{
    MasterName: "mymaster",
    SentinelAddrs: addrs,
    RouteRandomly: true,
})
Defensive patterns

Strategy: validation

Validate before calling

if opt.RouteRandomly {
    return errors.New("RouteRandomly requires NewFailoverClusterClient, not NewFailoverClient")
}

Prevention

When it happens

Trigger: Calling redis.NewFailoverClient with &redis.FailoverOptions{RouteRandomly: true, ...} set.

Common situations: Reusing cluster-style options structs for the sentinel client; toggling routing strategy via config without switching constructor; migrating from ClusterClient back to sentinel while leaving the flag set.

Related errors


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/72500f254ea1366d. Report an issue: GitHub.