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

  1. Retry the operation: the next topology refresh will re-attempt subscription on the recovered node.
  2. Verify all primary nodes are reachable and have consistent ACL/auth config.
  3. Ensure the cluster client's connection settings (timeout, retry) tolerate transient node unavailability during refresh.
  4. 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

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


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/560593852bcae26e. Report an issue: GitHub.