{"id":"471d16fc9519f7e8","repo":"redis/redis-py","slug":"len-uncovered-shard-channel-s-left-unreconcile","errorCode":null,"errorMessage":"{len(uncovered)} shard channel(s) left unreconciled; slot(s) not covered by the cluster: {uncovered!r}","messagePattern":"(.+?) shard channel\\(s\\) left unreconciled; slot\\(s\\) not covered by the cluster: (.+?)","errorType":"exception","errorClass":"SlotNotCoveredError","httpStatus":null,"severity":"error","filePath":"redis/cluster.py","lineNumber":3338,"sourceCode":"                        e,\n                    )\n                    if first_migrate_error is None:\n                        first_migrate_error = e\n                    continue\n            # Garbage-collect per-node pubsubs that no longer hold any\n            # subscription so their connections are released.\n            for name, pubsub in list(self.node_pubsub_mapping.items()):\n                if not pubsub.subscribed:\n                    try:\n                        pubsub.reset()\n                    except Exception:\n                        pass\n                    self.node_pubsub_mapping.pop(name, None)\n        if uncovered:\n            # Surface the uncovered channels so the caller (and observer\n            # notification path) knows reconciliation was incomplete. All\n            # coverable siblings have already been migrated above.\n            raise SlotNotCoveredError(\n                f\"{len(uncovered)} shard channel(s) left unreconciled; \"\n                f\"slot(s) not covered by the cluster: {uncovered!r}\"\n            )\n        if first_migrate_error is not None and not made_progress:\n            # Every migration attempted in this pass failed transiently and\n            # nothing else made progress. Re-raise the first caught error\n            # (typically the root cause; later failures are often downstream\n            # symptoms of the same unreachable node) so the worker's done-\n            # callback surfaces a single representative failure through the\n            # same logger channel used for SlotNotCoveredError. Per-channel\n            # WARNINGs above preserve the full forensic detail.\n            raise first_migrate_error\n\n    def _migrate_shard_channel(self, channel, handler, old_name, new_node):\n        # Detach from the old per-node pubsub, best-effort: the old node may\n        # already be unreachable during migration / failover.\n        if old_name and old_name in self.node_pubsub_mapping:\n            old_pubsub = self.node_pubsub_mapping[old_name]","sourceCodeStart":3320,"sourceCodeEnd":3356,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/cluster.py#L3320-L3356","documentation":"Error \"{len(uncovered)} shard channel(s) left unreconciled; slot(s) not covered by the cluster: {uncovered!r}\" thrown in redis/redis-py.","triggerScenarios":"Thrown at redis/cluster.py:3338 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}