go-redis/redis · critical

redis: cluster has no nodes

Error message

redis: cluster has no nodes

What it means

errClusterNoNodes (osscluster.go:37) is returned when a ClusterClient has zero known nodes to route to. It is produced at seven sites: cluster address list being empty after Close/teardown (osscluster.go:701), keyless command routing with no masters (osscluster.go:2949), arbitrary/all-node/all-shard fan-out with empty state (osscluster_router.go:76,92,106,317), and topology-load paths (osscluster.go:1866,1912). It means the cluster client has no usable topology.

Source

Thrown at osscluster.go:37

	"time"

	"github.com/redis/go-redis/v9/auth"
	"github.com/redis/go-redis/v9/internal"
	"github.com/redis/go-redis/v9/internal/hashtag"
	"github.com/redis/go-redis/v9/internal/otel"
	"github.com/redis/go-redis/v9/internal/pool"
	"github.com/redis/go-redis/v9/internal/proto"
	"github.com/redis/go-redis/v9/internal/routing"
	"github.com/redis/go-redis/v9/maintnotifications"
	"github.com/redis/go-redis/v9/push"
)

const (
	minLatencyMeasurementInterval = 10 * time.Second
)

var (
	errClusterNoNodes = errors.New("redis: cluster has no nodes")
	errNoWatchKeys    = errors.New("redis: Watch requires at least one key")
	errWatchCrosslot  = errors.New("redis: Watch requires all keys to be in the same slot")
)

// ClusterOptions are used to configure a cluster client and should be
// passed to NewClusterClient.
type ClusterOptions struct {
	// A seed list of host:port addresses of cluster nodes.
	Addrs []string

	// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.
	ClientName string

	// NewClient creates a cluster node client with provided name and options.
	// If NewClient is set by the user, the user is responsible for handling maintnotifications upgrades and push notifications.
	NewClient func(opt *Options) *Client

	// The maximum number of retries before giving up. Command is retried

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Provide at least one reachable seed node in ClusterOptions.Addrs.
  2. Verify the seed node is up and reachable (telnet/redis-cli CLUSTER NODES) from the client host.
  3. Do not issue commands on a client after Close(); construct a fresh one.
  4. Check that the cluster actually has masters (CLUSTER NODES); if all masters are down, restore them before retrying.
  5. Add a Dialer with retries/backoff and confirm network/DNS to the seed resolves.

Example fix

// before
c := redis.NewClusterClient(&redis.ClusterOptions{Addrs: nil})
// any command -> errClusterNoNodes

// after
c := redis.NewClusterClient(&redis.ClusterOptions{
  Addrs: []string{"redis-node-0:6379", "redis-node-1:6379", "redis-node-2:6379"},
})
Defensive patterns

Strategy: validation

Validate before calling

if len(clusterOpts.Addrs) == 0 {
    return fmt.Errorf("cluster client requires at least one seed node address")
}
// optionally liveness-check a seed before constructing the client
for _, a := range clusterOpts.Addrs {
    if c, err := net.DialTimeout("tcp", a, 2*time.Second); err == nil {
        c.Close()
        break
    }
}

Try / catch

err := c.Ping(ctx).Err()
if errors.Is(err, redis.Nil) == false && err != nil {
    if strings.Contains(err.Error(), "cluster has no nodes") {
        // seeds empty or unreachable: reconfigure Addrs and recreate client
    }
}

Prevention

When it happens

Trigger: Issuing a command on a ClusterClient whose Addrs list is empty, or after the cluster state failed to load (all nodes unreachable at startup), or after the client was Closed (clusterNodes closed, addrs emptied). Keyless commands (no slot) hit it when state.Masters is empty; fan-out commands (KEYS, DBSIZE across nodes) hit it when state has no nodes at all.

Common situations: Constructing NewClusterClient(&ClusterOptions{Addrs: nil}); all seed nodes unreachable so the initial CLUSTER SLOTS fails and state is empty; using a client after Close(); a cluster that lost all its masters; misconfigured load balancer returning nothing for the seed address.

Related errors


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