{"id":"d89b2e1edf978300","repo":"redis/redis-py","slug":"channel-channel-has-no-handler-registered-d89b2e","errorCode":null,"errorMessage":"Channel: '{channel}' has no handler registered","messagePattern":"Channel: '(.+?)' has no handler registered","errorType":"exception","errorClass":"PubSubError","httpStatus":null,"severity":"error","filePath":"redis/client.py","lineNumber":1727,"sourceCode":"        elif message_type != \"pong\":\n            # this is a subscribe/unsubscribe message. ignore if we don't\n            # want them\n            if ignore_subscribe_messages or self.ignore_subscribe_messages:\n                return None\n\n        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()","sourceCodeStart":1709,"sourceCodeEnd":1745,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/client.py#L1709-L1745","documentation":"Raised in `PubSub.run_in_thread` when iterating `self.channels` and finding a subscription whose handler is None. `run_in_thread` requires every registered channel to have a callback (the thread dispatches messages via these handlers internally), so a None handler is treated as a configuration error and raises PubSubError before starting the worker thread.","triggerScenarios":"Subscribing with `ps.subscribe('ch')` (no callback) and then calling `ps.run_in_thread()`. The plain `subscribe()` call stores None as the handler; run_in_thread validates that handlers exist for every channel and rejects the configuration. To use run_in_thread you must subscribe with a callable: `ps.subscribe(ch=handler)`.","commonSituations":"Mixing the polling API (subscribe + get_message) with the threaded API (run_in_thread); porting code from a get_message loop to a worker thread without adding per-channel callbacks.","solutions":["Pass a handler when subscribing for threaded use: `ps.subscribe(my_channel=my_handler)`.","Ensure every already-subscribed channel has a handler — re-subscribe with handlers for any that are missing.","If you want to poll manually instead of using callbacks, do not call run_in_thread; use a get_message loop in your own thread."],"exampleFix":"# before\nps.subscribe('events')\nps.run_in_thread()  # raises: Channel 'events' has no handler registered\n\n# after\ndef on_event(msg):\n    print(msg)\nps.subscribe(events=on_event)\nps.run_in_thread()","handlingStrategy":"validation","validationCode":"# Before run_in_thread, verify every channel has a handler\nif any(h is None for h in ps.channels.values()):\n    raise RuntimeError('Register handlers for all channels before run_in_thread')\nps.run_in_thread()","typeGuard":"def channels_have_handlers(ps) -> bool:\n    return all(h is not None for h in ps.channels.values())","tryCatchPattern":null,"preventionTips":["Use subscribe(channel=handler) form when planning to use run_in_thread.","Never mix plain subscribe() with run_in_thread."],"tags":["pubsub","threading","callbacks"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}