redis/redis-py · critical · RedisClusterException

All slots are not covered after query all startup_nodes.

Error message

All slots are not covered after query all startup_nodes. {len(tmp_slots)} of {REDIS_CLUSTER_HASH_SLOTS} covered...

What it means

Raised as a RedisClusterException after successfully querying all startup nodes when the combined slot coverage is incomplete (not all 16384 slots are covered) and require_full_coverage is True (the default). The message reports how many of the 16384 slots are covered. The guard is at cluster.py:2783-2790. This prevents the client from starting in a state where some keys would be unroutable.

Solutions

  1. Fix the cluster so all 16384 slots are covered: use redis-cli --cluster fix or redis-cli --cluster rebalance to assign uncovered slots.
  2. If you intentionally want to tolerate partial coverage, set require_full_coverage=False (but commands hitting uncovered slots will then fail at execution time with error 210).
  3. Wait for the cluster to finish creating/resharding and retry the client connection.

Example fix

// before
client = RedisCluster(host, port, require_full_coverage=True)  # cluster not fully covered

// after (tolerate partial coverage)
client = RedisCluster(host, port, require_full_coverage=False)
Defensive patterns

Strategy: validation

Validate before calling

import redis
# Check slot coverage before connecting
standalone = redis.Redis(host, port)
slots = standalone.cluster('SLOTS')
covered = set()
for s in slots:
    for i in range(int(s[0]), int(s[1]) + 1):
        covered.add(i)
if len(covered) < 16384:
    missing = set(range(16384)) - covered
    print(f'{len(missing)} slots uncovered; fix cluster or set require_full_coverage=False')

Type guard

def cluster_has_full_coverage(host: str, port: int) -> bool:
    import redis
    standalone = redis.Redis(host, port)
    slots = standalone.cluster('SLOTS')
    covered = set()
    for s in slots:
        covered.update(range(int(s[0]), int(s[1]) + 1))
    return len(covered) == 16384

Try / catch

from redis.exceptions import RedisClusterException
try:
    client = RedisCluster(host, port, require_full_coverage=True)
except RedisClusterException as e:
    if 'All slots are not covered' in str(e):
        # tolerate partial coverage if acceptable
        client = RedisCluster(host, port, require_full_coverage=False)

Prevention

When it happens

Trigger: Constructing RedisCluster(require_full_coverage=True) when the cluster has slots not assigned to any node (e.g., a cluster still being created, or a node holding slots has been removed without reassigning them). check_slots_coverage(tmp_slots) returns False.

Common situations: Cluster creation is incomplete (not all slots assigned), a primary holding slots failed and its slots were not picked up by replicas, or the cluster is mid-resharding during client init.

Related errors


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

Appendix: source

Thrown at redis/cluster.py:2786

                if fully_covered:
                    # Don't need to continue to the next startup node if all
                    # slots are 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

            # Create Redis connections to all nodes
            self.create_redis_connections(list(tmp_nodes_cache.values()))

            # 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
            with self._lock:
                self.nodes_cache = tmp_nodes_cache
                self.slots_cache = tmp_slots
                # Set the default node
                self.default_node = self.get_nodes_by_server_type(PRIMARY)[0]
                if self._dynamic_startup_nodes:
                    # Populate the startup nodes with all discovered nodes
                    self.startup_nodes = tmp_nodes_cache
                # Increment the epoch to signal that initialization has completed
                self._epoch += 1
            # Dispatch so listeners (e.g. ClusterPubSub) can reconcile per-node
            # state after slot ownership may have changed. A listener must not

View on GitHub (pinned to 6a6b581b48)