{"record":{"id":"06f569361e5739d4","repo":"redis/redis-py","slug":"pubsub-is-not-supported-for-rediscluster","errorCode":null,"errorMessage":"PubSub is not supported for RedisCluster","messagePattern":"PubSub is not supported for RedisCluster","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/multidb/command_executor.py","lineNumber":224,"sourceCode":"    def active_pubsub(self) -> Optional[PubSub]:\n        return self._active_pubsub\n\n    @active_pubsub.setter\n    def active_pubsub(self, pubsub: PubSub) -> None:\n        self._active_pubsub = pubsub\n\n    @property\n    def failover_strategy_executor(self) -> FailoverStrategyExecutor:\n        return self._failover_strategy_executor\n\n    @property\n    def command_retry(self) -> Retry:\n        return self._command_retry\n\n    def pubsub(self, **kwargs):\n        if self._active_pubsub is None:\n            if isinstance(self._active_database.client, RedisCluster):\n                raise ValueError(\"PubSub is not supported for RedisCluster\")\n\n            self._active_pubsub = self._active_database.client.pubsub(**kwargs)\n            self._active_pubsub_kwargs = kwargs\n\n    async def execute_command(self, *args, **options):\n        async def callback():\n            response = await self._active_database.client.execute_command(\n                *args, **options\n            )\n            await self._register_command_execution(args)\n            return response\n\n        return await self._execute_with_failure_detection(callback, args)\n\n    async def execute_pipeline(self, command_stack: tuple):\n        async def callback():\n            async with self._active_database.client.pipeline() as pipe:\n                for command, options in command_stack:","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/multidb/command_executor.py#L206-L242","documentation":"Raised as ValueError by DefaultCommandExecutor.pubsub() (command_executor.py:222-224) when pub/sub is first requested and the active database's underlying client is a RedisCluster. The multi-database PubSub wrapper delegates to a single active connection and is not built to fan out cluster pub/sub subscriptions, so it refuses creation rather than producing partial/inconsistent subscriptions.","triggerScenarios":"Calling await client.pubsub(...) on a MultiDBClient whose active database was configured with client_class=RedisCluster (or a cluster URL), or after failover promoted a cluster database to active. The check fires the first time pubsub() is called (when self._active_pubsub is None).","commonSituations":"Mixing Redis Cluster and standalone Redis in an Active-Active topology and trying to use pub/sub; pointing a DatabaseConfig at a redis://cluster URL with RedisCluster as client_class and then subscribing; failover landing on a cluster member.","solutions":["Use standalone redis.asyncio.Redis databases (client_class=Redis) in the MultiDBClient if pub/sub is required.","For cluster pub/sub, operate a separate dedicated RedisCluster client outside MultiDBClient.","Before subscribing, verify the active database is non-cluster: assert not isinstance(client.command_executor.active_database.client, RedisCluster).","Design topology so the pub/sub-capable database has the highest weight and is active at startup."],"exampleFix":"// before\nconfig = MultiDbConfig(\n    databases_config=[DatabaseConfig(from_url=\"redis://cluster:6379\", client_kwargs={...})],\n)\nclient = MultiDbConfig(config); client._config.client_class = RedisCluster\npubsub = await client.pubsub()  # ValueError\n\n// after - use a standalone Redis for the pub/sub-capable database\nconfig = MultiDbConfig(\n    databases_config=[DatabaseConfig(from_url=\"redis://standalone:6379\")],\n    client_class=Redis,\n)\nclient = MultiDBClient(config)\npubsub = await client.pubsub()","handlingStrategy":"validation","validationCode":"from redis.asyncio import RedisCluster\n\ndef active_supports_pubsub(client) -> bool:\n    active = client.command_executor.active_database\n    return active is not None and not isinstance(active.client, RedisCluster)\n\n# before subscribing:\nif not active_supports_pubsub(client):\n    raise NotImplementedError(\"pub/sub requires a non-cluster active database\")\npubsub = await client.pubsub()","typeGuard":"from redis.asyncio import Redis, RedisCluster\n\ndef active_is_standalone(client) -> bool:\n    active = client.command_executor.active_database\n    return active is not None and isinstance(active.client, Redis)","tryCatchPattern":"try:\n    pubsub = await client.pubsub()\nexcept ValueError as e:\n    if \"PubSub is not supported for RedisCluster\" in str(e):\n        # route pub/sub to a dedicated standalone Redis client instead\n        pubsub = standalone_redis.pubsub()\n    else:\n        raise","preventionTips":["Keep the pub/sub-capable database as a standalone redis.asyncio.Redis (client_class=Redis).","Give the standalone pub/sub database the highest weight so it is active at startup.","For cluster pub/sub, run a separate RedisCluster client outside MultiDBClient.","Assert the active DB is non-cluster before calling pubsub()."],"tags":["multidb","pubsub","cluster","unsupported","validation"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}