{"id":"2ef6422b17b8e47f","repo":"redis/redis-py","slug":"shard-channel-s-channel-has-no-handler-regist","errorCode":null,"errorMessage":"Shard Channel: '{s_channel}' has no handler registered","messagePattern":"Shard Channel: '(.+?)' has no handler registered","errorType":"exception","errorClass":"PubSubError","httpStatus":null,"severity":"error","filePath":"redis/client.py","lineNumber":1733,"sourceCode":"        return message\n\n    def run_in_thread(\n        self,\n        sleep_time: float = 0.0,\n        daemon: bool = False,\n        exception_handler: Optional[Callable] = None,\n        pubsub=None,\n        sharded_pubsub: bool = False,\n    ) -> \"PubSubWorkerThread\":\n        for channel, handler in self.channels.items():\n            if handler is None:\n                raise PubSubError(f\"Channel: '{channel}' has no handler registered\")\n        for pattern, handler in self.patterns.items():\n            if handler is None:\n                raise PubSubError(f\"Pattern: '{pattern}' has no handler registered\")\n        for s_channel, handler in self.shard_channels.items():\n            if handler is None:\n                raise PubSubError(\n                    f\"Shard Channel: '{s_channel}' has no handler registered\"\n                )\n\n        pubsub = self if pubsub is None else pubsub\n        thread = PubSubWorkerThread(\n            pubsub,\n            sleep_time,\n            daemon=daemon,\n            exception_handler=exception_handler,\n            sharded_pubsub=sharded_pubsub,\n        )\n        thread.start()\n        return thread\n\n\nclass PubSubWorkerThread(threading.Thread):\n    def __init__(\n        self,","sourceCodeStart":1715,"sourceCodeEnd":1751,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/client.py#L1715-L1751","documentation":"Raised in `PubSub.run_in_thread` when a shard-channel subscription (`ssubscribe`) has a None handler. Shard pubsub (Redis 7.0+) routes smessage frames by shard channel; the threaded dispatcher needs a handler in `self.shard_channels` for each, so a None handler raises PubSubError before the thread starts.","triggerScenarios":"Calling `ps.ssubscribe('channel')` (no callback) and then `ps.run_in_thread(sharded_pubsub=True)`. For the shard worker to dispatch smessage frames you must register a handler with `ps.ssubscribe(**{channel: handler})`.","commonSituations":"Adopting Redis 7 shard pubsub and reusing the plain-subscribe pattern (no callback) that worked with a manual loop; forgetting to pass `sharded_pubsub=True` to run_in_thread when using shard channels.","solutions":["Subscribe to shard channels with a handler: `ps.ssubscribe(**{'channel': on_shard_msg})`.","Pass `sharded_pubsub=True` to `run_in_thread` when your subscriptions are shard channels.","Use a manual get_message loop if you prefer not to use callbacks."],"exampleFix":"# before\nps.ssubscribe('orders')\nps.run_in_thread(sharded_pubsub=True)  # raises\n\n# after\ndef on_order(msg):\n    ...\nps.ssubscribe(**{'orders': on_order})\nps.run_in_thread(sharded_pubsub=True)","handlingStrategy":"validation","validationCode":"if any(h is None for h in ps.shard_channels.values()):\n    raise RuntimeError('Register handlers for all shard channels before run_in_thread')\nps.run_in_thread(sharded_pubsub=True)","typeGuard":"def shard_channels_have_handlers(ps) -> bool:\n    return all(h is not None for h in ps.shard_channels.values())","tryCatchPattern":null,"preventionTips":["Use ssubscribe(**{channel: handler}) for threaded shard pubsub.","Pass sharded_pubsub=True to run_in_thread."],"tags":["pubsub","threading","sharded","callbacks","redis7"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}