{"id":"7903ba1963c68876","repo":"go-redis/redis","slug":"redis-cluster-has-no-nodes","errorCode":null,"errorMessage":"redis: cluster has no nodes","messagePattern":"redis: cluster has no nodes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"osscluster.go","lineNumber":37,"sourceCode":"\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/auth\"\n\t\"github.com/redis/go-redis/v9/internal\"\n\t\"github.com/redis/go-redis/v9/internal/hashtag\"\n\t\"github.com/redis/go-redis/v9/internal/otel\"\n\t\"github.com/redis/go-redis/v9/internal/pool\"\n\t\"github.com/redis/go-redis/v9/internal/proto\"\n\t\"github.com/redis/go-redis/v9/internal/routing\"\n\t\"github.com/redis/go-redis/v9/maintnotifications\"\n\t\"github.com/redis/go-redis/v9/push\"\n)\n\nconst (\n\tminLatencyMeasurementInterval = 10 * time.Second\n)\n\nvar (\n\terrClusterNoNodes = errors.New(\"redis: cluster has no nodes\")\n\terrNoWatchKeys    = errors.New(\"redis: Watch requires at least one key\")\n\terrWatchCrosslot  = errors.New(\"redis: Watch requires all keys to be in the same slot\")\n)\n\n// ClusterOptions are used to configure a cluster client and should be\n// passed to NewClusterClient.\ntype ClusterOptions struct {\n\t// A seed list of host:port addresses of cluster nodes.\n\tAddrs []string\n\n\t// ClientName will execute the `CLIENT SETNAME ClientName` command for each conn.\n\tClientName string\n\n\t// NewClient creates a cluster node client with provided name and options.\n\t// If NewClient is set by the user, the user is responsible for handling maintnotifications upgrades and push notifications.\n\tNewClient func(opt *Options) *Client\n\n\t// The maximum number of retries before giving up. Command is retried","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/osscluster.go#L19-L55","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Provide at least one reachable seed node in ClusterOptions.Addrs.","Verify the seed node is up and reachable (telnet/redis-cli CLUSTER NODES) from the client host.","Do not issue commands on a client after Close(); construct a fresh one.","Check that the cluster actually has masters (CLUSTER NODES); if all masters are down, restore them before retrying.","Add a Dialer with retries/backoff and confirm network/DNS to the seed resolves."],"exampleFix":"// before\nc := redis.NewClusterClient(&redis.ClusterOptions{Addrs: nil})\n// any command -> errClusterNoNodes\n\n// after\nc := redis.NewClusterClient(&redis.ClusterOptions{\n  Addrs: []string{\"redis-node-0:6379\", \"redis-node-1:6379\", \"redis-node-2:6379\"},\n})","handlingStrategy":"validation","validationCode":"if len(clusterOpts.Addrs) == 0 {\n    return fmt.Errorf(\"cluster client requires at least one seed node address\")\n}\n// optionally liveness-check a seed before constructing the client\nfor _, a := range clusterOpts.Addrs {\n    if c, err := net.DialTimeout(\"tcp\", a, 2*time.Second); err == nil {\n        c.Close()\n        break\n    }\n}","typeGuard":null,"tryCatchPattern":"err := c.Ping(ctx).Err()\nif errors.Is(err, redis.Nil) == false && err != nil {\n    if strings.Contains(err.Error(), \"cluster has no nodes\") {\n        // seeds empty or unreachable: reconfigure Addrs and recreate client\n    }\n}","preventionTips":["Always pass >=1 reachable seed node in ClusterOptions.Addrs.","Don't issue commands after Close().","Add health checks / retries on the seed dialer.","Confirm the cluster has masters via CLUSTER NODES when debugging."],"tags":["cluster","routing","topology","config","runtime"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}