redis/redis-py · critical · RedisClusterException

Redis Cluster cannot be connected. Please provide at least…

Error message

Redis Cluster cannot be connected. Please provide at least one reachable node: {str(exception)}

What it means

Raised at the end of initialize() when none of the startup nodes (plus any additional_startup_nodes) could be contacted. The original connection exception is included so you can see the underlying socket/auth/timeout cause.

Solutions

  1. Confirm network reachability: telnet/nc to host:port from the client host.
  2. Verify host and port values and that the cluster nodes are actually running.
  3. Check credentials: if AUTH is required, pass password=/credential_provider= matching the cluster's ACL.
  4. For TLS clusters, ensure ssl=True and correct ca_certs; for plaintext, ensure ssl is not forced.
  5. Inspect str(exception) in the message for the real cause (timeout vs auth vs connection refused).

Example fix

// before
rc = RedisCluster(host='redis-prod', port=6379)  # wrong host/port

// after
rc = RedisCluster(host='redis-prod', port=7000, password=os.environ['REDIS_PW'])
# verify first:
# nc -zv redis-prod 7000
Defensive patterns

Strategy: try-catch

Validate before calling

import socket

def reachable(host, port, timeout=2):
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False

if not all(reachable(h, p) for h, p in seeds):
    raise RuntimeError('Some cluster seed nodes unreachable')
rc = RedisCluster(startup_nodes=[ClusterNode(h, p) for h, p in seeds])

Type guard

null

Try / catch

from redis.exceptions import RedisClusterException
import asyncio
for attempt in range(5):
    try:
        await rc.initialize()
        break
    except RedisClusterException as e:
        if 'cannot be connected' not in str(e):
            raise
        await asyncio.sleep(min(2 ** attempt, 30))
else:
    raise

Prevention

When it happens

Trigger: All startup_nodes are unreachable: wrong host/port, network partition, firewall, TLS mismatch, auth failure, or every node is down. startup_nodes_reachable stays False and the last exception bubbles up.

Common situations: DNS resolving to a dead endpoint; security group / firewall blocking the port; AUTH/ACL password wrong so every node rejects the connection; client pointed at the wrong environment.

Related errors


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

Appendix: source

Thrown at redis/asyncio/cluster.py:2372

                                )

                                if len(disagreements) > 5:
                                    raise RedisClusterException(
                                        f"startup_nodes could not agree on a valid "
                                        f"slots cache: {', '.join(disagreements)}"
                                    )

                # Validate if all slots are covered or if we should try next startup node
                fully_covered = True
                for i in range(REDIS_CLUSTER_HASH_SLOTS):
                    if i not in tmp_slots:
                        fully_covered = False
                        break
                if fully_covered:
                    break

            if not startup_nodes_reachable:
                raise RedisClusterException(
                    f"Redis Cluster cannot be connected. Please provide at least "
                    f"one reachable node: {str(exception)}"
                ) from exception

            # Check if the slots are not fully covered
            if not fully_covered and self.require_full_coverage:
                # Despite the requirement that the slots be covered, there
                # isn't a full coverage
                raise RedisClusterException(
                    f"All slots are not covered after query all startup_nodes. "
                    f"{len(tmp_slots)} of {REDIS_CLUSTER_HASH_SLOTS} "
                    f"covered..."
                )

            # Set the tmp variables to the real variables
            self.set_nodes(self.nodes_cache, tmp_nodes_cache, remove_old=True)
            # tmp_slots was built from CLUSTER SLOTS responses and can contain
            # newly-created ClusterNode objects for nodes we already know about.

View on GitHub (pinned to 6a6b581b48)