redis/redis-py · error · RuntimeError
pubsub connection not set: did you forget to call subscribe(
Error message
pubsub connection not set: did you forget to call subscribe() or psubscribe()?
What it means
Raised in `PubSub.parse_response` when `self.connection is None`. The pubsub connection is only created lazily inside `execute_command` the first time a subscribe-type command is issued. Calling `parse_response()` (or `get_message()`, which wraps it) before any subscribe means no connection exists, so the library raises a RuntimeError pointing at the missing subscribe call.
Source
Thrown at redis/client.py:1377
block=False when a timeout is provided, and block=True when timeout=None.
Example:
# Block indefinitely (timeout is ignored)
response = pubsub.parse_response(block=True, timeout=0.1)
# Non-blocking with 0.1 second timeout
response = pubsub.parse_response(block=False, timeout=0.1)
# Non-blocking, return immediately
response = pubsub.parse_response(block=False, timeout=0)
# Recommended: use get_message() instead
msg = pubsub.get_message(timeout=0.1) # automatically sets block=False
msg = pubsub.get_message(timeout=None) # automatically sets block=True
"""
conn = self.connection
if conn is None:
raise RuntimeError(
"pubsub connection not set: "
"did you forget to call subscribe() or psubscribe()?"
)
self.check_health()
def try_read():
if not block:
if not conn.can_read(timeout=timeout):
return None
read_timeout = timeout
else:
conn.connect()
# Block indefinitely waiting for a pubsub message. timeout=None
# makes the socket layer call sock.settimeout(None) for this read
# (and restore the original socket_timeout afterwards), so the
# configured socket_timeout does not abort the read.
read_timeout = NoneView on GitHub (pinned to da03cdc7e8)
Solutions
- Call `ps.subscribe(channel)` (or psubscribe/ssubscribe) before the first `ps.get_message()` / `ps.parse_response()`.
- After any `ps.close()` or `ps.reset()`, re-subscribe before reading again.
- Prefer `ps.get_message(timeout=...)` over manual `parse_response` — it handles the subscribe lifecycle.
- If using an exception handler that resets the pubsub on error, ensure the recovery path re-invokes subscribe.
Example fix
# before
ps = client.pubsub()
msg = ps.get_message(timeout=1.0) # raises RuntimeError
# after
ps = client.pubsub()
ps.subscribe('events')
msg = ps.get_message(timeout=1.0) Defensive patterns
Strategy: validation
Validate before calling
ps = client.pubsub()
if not ps.subscribed:
ps.subscribe('events') # ensure a connection exists before reading Type guard
def can_read_pubsub(ps) -> bool:
return ps.connection is not None and ps.subscribed Prevention
- Always call subscribe/psubscribe before the first get_message.
- Prefer get_message over manual parse_response.
- Re-subscribe after close()/reset().
When it happens
Trigger: Calling `pubsub.parse_response(...)` or `pubsub.get_message(...)` immediately after `client.pubsub()` without first calling `subscribe()`, `psubscribe()`, or `ssubscribe()`. Also happens if the PubSub was closed/reset (connection released) and then read from again without re-subscribing.
Common situations: Order-of-operations bugs in event loops; wrapping `get_message` in a retry loop that survives a close without re-subscribing; copy-paste from examples that omitted the subscribe line; calling parse_response manually instead of via get_message.
Related errors
- Buffer is closed.
- Connection closed by server.
- pubsub connection not set: did you forget to call subscribe(
- Channel: '{channel}' has no handler registered
- Pattern: '{pattern}' has no handler registered
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/ef8e08c578caca79.json.
Report an issue: GitHub.