redis/redis-py · error · ConnectionError
Failed to subscribe to cluster nodes: {failed_nodes}
Error message
Failed to subscribe to cluster nodes: {failed_nodes} What it means
During a topology refresh, ClusterKeyspaceNotifications (redis/keyspace_notifications.py:2164) tries to subscribe each newly-discovered primary node to the currently-registered patterns/channels. If the psubscribe/subscribe call for a node raises, that node is cleaned up, recorded in failed_nodes, and after all new nodes are attempted a ConnectionError listing the failed node names is raised. It is raised only when at least one node could not be (re)subscribed.
Source
Thrown at redis/keyspace_notifications.py:2164
new_nodes = set(current_primaries.keys()) - set(self._node_pubsubs.keys())
failed_nodes: list[str] = []
for node_name in new_nodes:
node = current_primaries[node_name]
pubsub = self._ensure_node_pubsub(node)
try:
if self._subscribed_patterns:
pubsub.psubscribe(**self._subscribed_patterns)
if self._subscribed_channels:
pubsub.subscribe(**self._subscribed_channels)
except Exception:
# Subscription failed - remove from dict so retry is possible
self._cleanup_node(node_name)
failed_nodes.append(node_name)
# Raise after attempting all nodes so we don't skip any
if failed_nodes:
raise ConnectionError(
f"Failed to subscribe to cluster nodes: {', '.join(failed_nodes)}"
)
def close(self):
"""Close all pubsub connections and clean up resources."""
self._closed = True
for node_name in list(self._node_pubsubs.keys()):
self._cleanup_node(node_name)
self._subscribed_patterns.clear()
self._subscribed_channels.clear()
View on GitHub (pinned to 6a6b581b48)
Solutions
- Retry the operation: the next topology refresh will re-attempt subscription on the recovered node.
- Verify all primary nodes are reachable and have consistent ACL/auth config.
- Ensure the cluster client's connection settings (timeout, retry) tolerate transient node unavailability during refresh.
- Check maxclients / node health for the named failed nodes.
Example fix
// before
ckn.run_in_thread(poll_timeout=0.1) # raises during failover
// after
import time
from redis.exceptions import ConnectionError
for _ in range(10):
try:
ckn.run_in_thread(poll_timeout=0.1); break
except ConnectionError:
time.sleep(1) # wait for new primary to finish failover Defensive patterns
Strategy: retry
Validate before calling
def cluster_healthy(cluster) -> bool:
try:
primaries = cluster.get_primaries()
return all(cluster.ping(node) for node in primaries)
except Exception:
return False Try / catch
import time
from redis.exceptions import ConnectionError
for _ in range(10):
try:
ckn.run_in_thread(poll_timeout=0.1)
break
except ConnectionError:
time.sleep(1)
else:
raise Prevention
- Retry on the next topology refresh once unreachable primaries recover.
- Verify consistent ACL/auth across all cluster nodes.
- Tune connection timeout/retry so transient node unavailability during refresh is tolerated.
- Watch maxclients and node health for the named failed nodes.
When it happens
Trigger: A cluster failover/reshard adds new primaries while one or more of them are unreachable (network partition, still starting up, misconfigured), so the per-node psubscribe/subscribe throws during refresh. Also when a node rejects the pubsub connection (maxclients, auth).
Common situations: Right after a primary failover during which a node is briefly unavailable; partial network outage in multi-AZ cluster; rolling restart where nodes come back at different times; auth/ACL mismatch on a subset of nodes.
Related errors
- Slot "{slot}" is not covered by the cluster.
- READONLY command failed
- The requested node does not exist in the cluster.
- Slot "{slot}" is not covered by the cluster.
- No targets were found to execute {args} command on
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/560593852bcae26e.
Report an issue: GitHub.