{"record":{"id":"819a9b6c83b37b63","repo":"redis/redis-py","slug":"startup-nodes-could-not-agree-on-a-valid-slots-cac-819a9b","errorCode":null,"errorMessage":"startup_nodes could not agree on a valid slots cache: {', '.join(disagreements)}","messagePattern":"startup_nodes could not agree on a valid slots cache: (.+?)","errorType":"exception","errorClass":"RedisClusterException","httpStatus":null,"severity":"critical","filePath":"redis/cluster.py","lineNumber":2762,"sourceCode":"                        target_replica_node = self._get_or_create_cluster_node(\n                            host, port, REPLICA, tmp_nodes_cache\n                        )\n                        nodes_for_slot.append(target_replica_node)\n\n                    for i in range(int(slot[0]), int(slot[1]) + 1):\n                        if i not in tmp_slots:\n                            tmp_slots[i] = nodes_for_slot\n                        else:\n                            # Validate that 2 nodes want to use the same slot cache\n                            # setup\n                            tmp_slot = tmp_slots[i][0]\n                            if tmp_slot.name != target_node.name:\n                                disagreements.append(\n                                    f\"{tmp_slot.name} vs {target_node.name} on slot: {i}\"\n                                )\n\n                                if len(disagreements) > 5:\n                                    raise RedisClusterException(\n                                        f\"startup_nodes could not agree on a valid \"\n                                        f\"slots cache: {', '.join(disagreements)}\"\n                                    )\n\n                fully_covered = self.check_slots_coverage(tmp_slots)\n                if fully_covered:\n                    # Don't need to continue to the next startup node if all\n                    # slots are 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            # Create Redis connections to all nodes\n            self.create_redis_connections(list(tmp_nodes_cache.values()))","sourceCodeStart":2744,"sourceCodeEnd":2780,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/cluster.py#L2744-L2780","documentation":"Raised as a RedisClusterException during topology assembly when two different nodes both claim ownership of the same slot in CLUSTER SLOTS output, and the number of such disagreements exceeds 5. The client detects the conflict at cluster.py:2755-2765 (comparing tmp_slots[i][0].name vs target_node.name) and aborts because a contradictory slots cache is unsafe to use.","triggerScenarios":"During initialize() / topology refresh, CLUSTER SLOTS returns slot ranges where the same slot is assigned to two different primary nodes, producing more than 5 disagreements. This indicates a corrupted or split-brain cluster topology.","commonSituations":"Cluster is in a split-brain state, nodes have stale slot ownership info after a botched reshard or failover, or a misconfigured cluster has overlapping slot assignments.","solutions":["Inspect the cluster with CLUSTER NODES and CLUSTER SLOTS on each node to identify which nodes disagree on slot ownership.","Fix the slot assignments using CLUSTER SETSLOT / redis-cli --cluster fix to reconcile ownership.","If a node is permanently divergent, remove it from the cluster (CLUSTER FORGET) and re-add it correctly.","Restart the affected Redis nodes to re-sync cluster config from the persisted nodes.conf."],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"# Inspect CLUSTER SLOTS for overlapping slot ownership before connecting\nimport redis\nstandalone = redis.Redis(host, port)\nslots = standalone.cluster('SLOTS')\nowners = {}\nfor s in slots:\n    for i in range(int(s[0]), int(s[1]) + 1):\n        owner = s[2][2]  # node id of primary\n        if i in owners and owners[i] != owner:\n            print(f'Slot conflict: slot {i} claimed by {owners[i]} and {owner}')\n        owners[i] = owner","typeGuard":"null","tryCatchPattern":"from redis.exceptions import RedisClusterException\ntry:\n    client = RedisCluster(host, port)\nexcept RedisClusterException as e:\n    if 'could not agree' in str(e):\n        # run redis-cli --cluster fix, then retry\n        raise RuntimeError('Cluster has slot conflicts; run redis-cli --cluster fix') from e","preventionTips":["Use redis-cli --cluster check and --cluster fix to validate and repair slot assignments.","Monitor cluster health for split-brain conditions after failover.","Restart nodes with corrupt nodes.conf to re-sync topology."],"tags":["topology","split-brain","slot-conflict","cluster-health"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}