redis/redis-py · warning · ConnectionError

Failed to subscribe to cluster nodes: {', '.join(failed_node

Error message

Failed to subscribe to cluster nodes: {', '.join(failed_nodes)}

What it means

Raised as ConnectionError by ClusterKeyspaceNotifications.refresh_subscriptions() when one or more newly discovered primary nodes could not be subscribed to. The method attempts every new node, collects failures, then raises once with the list of failed node names. Existing subscriptions and cleanup of failed nodes still happen; the raise signals that the topology is not fully subscribed.

Source

Thrown at redis/asyncio/keyspace_notifications.py:1019

            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 = await self._ensure_node_pubsub(node)

                try:
                    if self._subscribed_patterns:
                        await pubsub.psubscribe(**self._subscribed_patterns)
                    if self._subscribed_channels:
                        await pubsub.subscribe(**self._subscribed_channels)
                except Exception:
                    # Subscription failed - remove from dict so retry is possible
                    await 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)}"
                )

    async def aclose(self):
        """Close all pubsub connections and clean up resources."""
        self._closed = True
        for node_name in list(self._node_pubsubs.keys()):
            await self._cleanup_node(node_name)
        self._subscribed_patterns.clear()
        self._subscribed_channels.clear()

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Retry refresh_subscriptions after a short backoff; the failed nodes are cleaned up so a later attempt re-subscribes them.
  2. Verify network reachability and ACL/credentials for the listed nodes.
  3. Ensure the cluster topology has stabilized (CLUSTER NODES) before retrying.
  4. If recurring, check the pubsub connection limits and per-node connection counts.

Example fix

// before
await notifier.refresh_subscriptions()  # raises on first transient failure
// after
for attempt in range(5):
    try:
        await notifier.refresh_subscriptions()
        break
    except ConnectionError:
        await asyncio.sleep(2 ** attempt)\nelse:\n    raise
Defensive patterns

Strategy: retry

Validate before calling

async def safe_refresh(notifier, attempts=5):
    for i in range(attempts):
        try:
            await notifier.refresh_subscriptions()
            return True
        except ConnectionError:
            await asyncio.sleep(2 ** i)
    return False

Type guard

def cluster_topology_stable(cluster) -> bool:
    # heuristically, all slots assigned and no FAIL/HANDSHAKE nodes
    nodes = cluster.cluster_nodes()
    return all(n['flags'] and 'fail' not in n['flags'] for n in nodes)

Try / catch

from redis.exceptions import ConnectionError
try:
    await notifier.refresh_subscriptions()
except ConnectionError as e:
    if 'Failed to subscribe' in str(e):
        await asyncio.sleep(backoff)
        await notifier.refresh_subscriptions()

Prevention

When it happens

Trigger: Cluster topology change (failover/scale-out) adds new primary nodes; refresh_subscriptions tries to psubscribe/subscribe the new nodes' pubsub connections and the subscribe call raises (network error, node unreachable, auth failure). All failing node names are aggregated into the message.

Common situations: Cluster failover in progress where a new primary is briefly unreachable; network partition; auth/ACL mismatch on a new primary; partial outage during scaling; calling refresh_subscriptions manually right after a topology change.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/c5ca167f28ea36cd.json. Report an issue: GitHub.