redis/redis-py · error · PubSubError

Shard Channel: '{s_channel}' has no handler registered

Error message

Shard Channel: '{s_channel}' has no handler registered

What it means

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.

Source

Thrown at redis/client.py:1733

        return message

    def run_in_thread(
        self,
        sleep_time: float = 0.0,
        daemon: bool = False,
        exception_handler: Optional[Callable] = None,
        pubsub=None,
        sharded_pubsub: bool = False,
    ) -> "PubSubWorkerThread":
        for channel, handler in self.channels.items():
            if handler is None:
                raise PubSubError(f"Channel: '{channel}' has no handler registered")
        for pattern, handler in self.patterns.items():
            if handler is None:
                raise PubSubError(f"Pattern: '{pattern}' has no handler registered")
        for s_channel, handler in self.shard_channels.items():
            if handler is None:
                raise PubSubError(
                    f"Shard Channel: '{s_channel}' has no handler registered"
                )

        pubsub = self if pubsub is None else pubsub
        thread = PubSubWorkerThread(
            pubsub,
            sleep_time,
            daemon=daemon,
            exception_handler=exception_handler,
            sharded_pubsub=sharded_pubsub,
        )
        thread.start()
        return thread


class PubSubWorkerThread(threading.Thread):
    def __init__(
        self,

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Subscribe to shard channels with a handler: `ps.ssubscribe(**{'channel': on_shard_msg})`.
  2. Pass `sharded_pubsub=True` to `run_in_thread` when your subscriptions are shard channels.
  3. Use a manual get_message loop if you prefer not to use callbacks.

Example fix

# before
ps.ssubscribe('orders')
ps.run_in_thread(sharded_pubsub=True)  # raises

# after
def on_order(msg):
    ...
ps.ssubscribe(**{'orders': on_order})
ps.run_in_thread(sharded_pubsub=True)
Defensive patterns

Strategy: validation

Validate before calling

if any(h is None for h in ps.shard_channels.values()):
    raise RuntimeError('Register handlers for all shard channels before run_in_thread')
ps.run_in_thread(sharded_pubsub=True)

Type guard

def shard_channels_have_handlers(ps) -> bool:
    return all(h is not None for h in ps.shard_channels.values())

Prevention

When it happens

Trigger: 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})`.

Common situations: 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.

Related errors


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