redis/redis-py · error · ValueError

PubSub is not supported for RedisCluster

Error message

PubSub is not supported for RedisCluster

What it means

Raised by `DefaultCommandExecutor.pubsub()` (redis/asyncio/multidb/command_executor.py:224) when the active database's underlying client is a `RedisCluster`. The multi-database PubSub abstraction assumes a standalone-style PubSub object; cluster PubSub has a different shape, so creating one through the executor is rejected with ValueError.

Source

Thrown at redis/asyncio/multidb/command_executor.py:224

    def active_pubsub(self) -> Optional[PubSub]:
        return self._active_pubsub

    @active_pubsub.setter
    def active_pubsub(self, pubsub: PubSub) -> None:
        self._active_pubsub = pubsub

    @property
    def failover_strategy_executor(self) -> FailoverStrategyExecutor:
        return self._failover_strategy_executor

    @property
    def command_retry(self) -> Retry:
        return self._command_retry

    def pubsub(self, **kwargs):
        if self._active_pubsub is None:
            if isinstance(self._active_database.client, RedisCluster):
                raise ValueError("PubSub is not supported for RedisCluster")

            self._active_pubsub = self._active_database.client.pubsub(**kwargs)
            self._active_pubsub_kwargs = kwargs

    async def execute_command(self, *args, **options):
        async def callback():
            response = await self._active_database.client.execute_command(
                *args, **options
            )
            await self._register_command_execution(args)
            return response

        return await self._execute_with_failure_detection(callback, args)

    async def execute_pipeline(self, command_stack: tuple):
        async def callback():
            async with self._active_database.client.pipeline() as pipe:
                for command, options in command_stack:

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Use a standalone `redis.asyncio.Redis` client (not via MultiDBClient) for pub/sub against a cluster endpoint, or use `RedisCluster.pubsub()` directly on a dedicated cluster client.
  2. Configure `MultiDbConfig.client_class=Redis` if pub/sub through the multi-database client is required and topology allows standalone connections.
  3. Subscribe before failover to a cluster DB, or restrict pub/sub usage to standalone-backed databases.

Example fix

# before
cfg = MultiDbConfig(databases_config=[...], client_class=RedisCluster)
client = MultiDBClient(cfg)
await client.initialize()
ps = await client.pubsub()  # ValueError: PubSub is not supported for RedisCluster

# after
import redis.asyncio as redis
cluster = redis.RedisCluster.from_url('redis://cluster:16379')
ps = cluster.pubsub()  # use the cluster client's own pubsub
Defensive patterns

Strategy: validation

Validate before calling

def can_pubsub(client) -> bool:
    # PubSub through MultiDBClient requires a non-cluster active DB
    from redis.asyncio import RedisCluster
    from redis.asyncio.multidb.client import MultiDBClient
    if not isinstance(client, MultiDBClient):
        return True
    active = client.command_executor.active_database
    return active is not None and not isinstance(active.client, RedisCluster)

Type guard

import redis.asyncio as aioredis
from redis.asyncio.multidb.client import MultiDBClient

def active_db_is_standalone(client) -> bool:
    if not isinstance(client, MultiDBClient):
        return True
    active = client.command_executor.active_database
    return active is not None and isinstance(active.client, aioredis.Redis)

Try / catch

try:
    ps = await client.pubsub()
except ValueError as e:
    if 'PubSub is not supported for RedisCluster' in str(e):
        # use a dedicated cluster client's pubsub instead
        cluster = redis.asyncio.RedisCluster.from_url(url)
        ps = cluster.pubsub()
    else:
        raise

Prevention

When it happens

Trigger: Calling `await multi_client.pubsub()` (or constructing the PubSub wrapper which calls `command_executor.pubsub()` at client.py:558) when `command_executor.active_database.client` is an `AsyncRedisCluster` instance — i.e. `MultiDbConfig.client_class = RedisCluster` and the active DB uses a cluster client.

Common situations: Configuring `client_class=RedisCluster` in MultiDbConfig and then trying to subscribe to pub/sub channels; failing over to a cluster-backed active database and then calling pubsub.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/06f569361e5739d4.json. Report an issue: GitHub.