{"record":{"id":"d71ad6a981a57c95","repo":"redis/redis-py","slug":"all-slots-are-not-covered-after-query-all-startup","errorCode":null,"errorMessage":"All slots are not covered after query all startup_nodes. {len(tmp_slots)} of {REDIS_CLUSTER_HASH_SLOTS} covered...","messagePattern":"All slots are not covered after query all startup_nodes\\. (.+?) of (.+?) covered\\.\\.\\.","errorType":"exception","errorClass":"RedisClusterException","httpStatus":null,"severity":"critical","filePath":"redis/asyncio/cluster.py","lineNumber":2381,"sourceCode":"                fully_covered = True\n                for i in range(REDIS_CLUSTER_HASH_SLOTS):\n                    if i not in tmp_slots:\n                        fully_covered = False\n                        break\n                if fully_covered:\n                    break\n\n            if not startup_nodes_reachable:\n                raise RedisClusterException(\n                    f\"Redis Cluster cannot be connected. Please provide at least \"\n                    f\"one reachable node: {str(exception)}\"\n                ) from exception\n\n            # Check if the slots are not fully covered\n            if not fully_covered and self.require_full_coverage:\n                # Despite the requirement that the slots be covered, there\n                # isn't a full coverage\n                raise RedisClusterException(\n                    f\"All slots are not covered after query all startup_nodes. \"\n                    f\"{len(tmp_slots)} of {REDIS_CLUSTER_HASH_SLOTS} \"\n                    f\"covered...\"\n                )\n\n            # Set the tmp variables to the real variables\n            self.set_nodes(self.nodes_cache, tmp_nodes_cache, remove_old=True)\n            # tmp_slots was built from CLUSTER SLOTS responses and can contain\n            # newly-created ClusterNode objects for nodes we already know about.\n            # Rebuild the slots cache with the preserved nodes_cache instances\n            # so existing per-node connection pools stay in use after refresh.\n            # Keep the shared node-list-per-slot-range shape from tmp_slots to\n            # avoid allocating a separate list for every slot.\n            node_lists_by_id: Dict[int, List[\"ClusterNode\"]] = {}\n            new_slots_cache: Dict[int, List[\"ClusterNode\"]] = {}\n            for slot, nodes in tmp_slots.items():\n                node_list_id = id(nodes)\n                slot_nodes = node_lists_by_id.get(node_list_id)","sourceCodeStart":2363,"sourceCodeEnd":2399,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/cluster.py#L2363-L2399","documentation":"Raised after initialize() contacts at least one node but the merged CLUSTER SLOTS responses still do not cover all 16384 slots, while require_full_coverage=True. The client is configured to refuse partial coverage, so it aborts startup with the count of covered slots.","triggerScenarios":"At least one startup node answered, but some slot ranges have no owner (unreachable primaries with no replicas, cluster still being created, or nodes that failed mid-build). require_full_coverage defaults True for the async cluster client.","commonSituations":"Cluster that has lost primaries for some slots without failing over; brand-new cluster not fully created (CLUSTER CREATE incomplete); subset of nodes down at client startup.","solutions":["Restore the downed primary or trigger manual failover so every slot is served.","Recreate/finish the cluster (redis-cli --cluster create / fix) so all slots are assigned.","If you can tolerate partial unavailability, construct the client with require_full_coverage=False.","Retry initialize() after cluster health is restored; the covered-slot count should reach 16384."],"exampleFix":"// before\nrc = RedisCluster(host='localhost', port=7000)  # partial cluster -> raises\n\n// after\n# fix cluster: redis-cli --cluster fix 127.0.0.1:7000\n# or tolerate partial coverage:\nrc = RedisCluster(host='localhost', port=7000, require_full_coverage=False)","handlingStrategy":"fallback","validationCode":"async def covered_slots(host, port):\n    from redis.asyncio import Redis\n    r = Redis(host=host, port=port)\n    try:\n        slots = await r.execute_command('CLUSTER', 'SLOTS')\n        covered = sum(int(s[1]) - int(s[0]) + 1 for s in slots)\n        return covered\n    finally:\n        await r.aclose()\n\nif await covered_slots(host, port) < 16384:\n    rc = RedisCluster(host=host, port=port, require_full_coverage=False)\nelse:\n    rc = RedisCluster(host=host, port=port)","typeGuard":"null","tryCatchPattern":"from redis.exceptions import RedisClusterException\ntry:\n    rc = RedisCluster(host=host, port=port)\n    await rc.initialize()\nexcept RedisClusterException as e:\n    if 'All slots are not covered' in str(e):\n        rc = RedisCluster(host=host, port=port, require_full_coverage=False)\n        await rc.initialize()","preventionTips":["Restore failed primaries or run redis-cli --cluster fix so all slots are owned.","If partial coverage is acceptable for your workload, set require_full_coverage=False explicitly.","Monitor slot coverage as part of cluster health checks."],"tags":["cluster","slots","coverage","init","availability"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}