{"record":{"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/6a6b581b48225afa0b76912d1028c6035baee932/redis/client.py#L1709-L1745","documentation":"Raised by PubSub.run_in_thread() when a subscribed channel has no message handler callback registered. run_in_thread dispatches incoming messages to per-channel handlers; if any channel was subscribed without a handler, the worker thread cannot route messages, so the library refuses to start it.","triggerScenarios":"Calling pubsub.subscribe(channel) (positional, no callback) followed by pubsub.run_in_thread(). The channels dict maps the channel to None, and the validation loop at client.py:1725 raises.","commonSituations":"Mixing the two subscribe styles: subscribe(name) for manual get_message() polling vs. subscribe(name=handler) for run_in_thread dispatch; refactoring from polling to threaded mode without adding handlers.","solutions":["Register a handler per channel: pubsub.subscribe(**{'channel': handler_fn}) or pubsub.subscribe(handler_fn, 'channel').","If you intend to poll manually with get_message(), do not call run_in_thread() — use a plain loop instead.","Ensure every channel in pubsub.channels has a non-None handler before calling run_in_thread()."],"exampleFix":"// before\npubsub.subscribe('alerts')\npubsub.run_in_thread()  # PubSubError\n\n// after\ndef on_alert(msg): ...\npubsub.subscribe(**{'alerts': on_alert})\npubsub.run_in_thread()","handlingStrategy":"validation","validationCode":"# Ensure every subscribed channel has a handler before starting the worker.\nmissing = [ch for ch, h in pubsub.channels.items() if h is None]\nif missing:\n    raise ValueError(f'Channels missing handlers: {missing}')\npubsub.run_in_thread()","typeGuard":"def all_channels_have_handlers(pubsub) -> bool:\n    return all(h is not None for h in pubsub.channels.values())","tryCatchPattern":"from redis.exceptions import PubSubError\ntry:\n    pubsub.run_in_thread()\nexcept PubSubError:\n    # register handlers then retry\n    for ch in list(pubsub.channels):\n        pubsub.channels[ch] = default_handler","preventionTips":["When adopting run_in_thread, switch to subscribe(**{name: handler}) form.","Do not mix polling-style subscribe(name) with run_in_thread().","Validate pubsub.channels has no None values before starting the worker."],"tags":["pubsub","threading","api-misuse"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}