{"id":"e91ee1f85c5c7166","repo":"redis/redis-py","slug":"pubsub-connection-not-set-did-you-forget-to-call","errorCode":null,"errorMessage":"pubsub connection not set: did you forget to call subscribe() or psubscribe()?","messagePattern":"pubsub connection not set: did you forget to call subscribe\\(\\) or psubscribe\\(\\)\\?","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/client.py","lineNumber":1424,"sourceCode":"            block=False when a timeout is provided, and block=True when timeout=None.\n\n        Example:\n            # Block indefinitely (timeout is ignored)\n            response = await pubsub.parse_response(block=True, timeout=0.1)\n\n            # Non-blocking with 0.1 second timeout\n            response = await pubsub.parse_response(block=False, timeout=0.1)\n\n            # Non-blocking, return immediately\n            response = await pubsub.parse_response(block=False, timeout=0)\n\n            # Recommended: use get_message() instead\n            msg = await pubsub.get_message(timeout=0.1)  # automatically sets block=False\n            msg = await pubsub.get_message(timeout=None)  # automatically sets block=True\n        \"\"\"\n        conn = self.connection\n        if conn is None:\n            raise RuntimeError(\n                \"pubsub connection not set: \"\n                \"did you forget to call subscribe() or psubscribe()?\"\n            )\n\n        await self.check_health()\n\n        if not conn.is_connected:\n            await conn.connect()\n\n        # Block=True: signal \"no timeout\" to conn.read_response via\n        # math.inf. The connection treats math.inf as the per-read\n        # opt-in for blocking indefinitely without falling back to\n        # self.socket_timeout. Reconnect/AUTH/HELLO/resubscribe\n        # operations performed by the retry layer continue to honor\n        # self.socket_timeout because they do not pass math.inf.\n        #\n        # TODO(next-major): when the async Connection.read_response\n        # default for ``timeout`` is changed to SENTINEL, passing","sourceCodeStart":1406,"sourceCodeEnd":1442,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/asyncio/client.py#L1406-L1442","documentation":"Raised by PubSub.parse_response (redis/asyncio/client.py:1424) when self.connection is None. The pub/sub connection is only allocated by subscribe()/psubscribe()/unsubscribe(); calling parse_response() (or any path that drives reads) before subscribing has no socket to read from, so the library raises a RuntimeError with an explanatory hint.","triggerScenarios":"Calling `await pubsub.parse_response(...)` or `await pubsub.get_message(...)` on a PubSub object obtained from `client.pubsub()` before any subscribe()/psubscribe() call. The connection field stays None until a subscription allocates a dedicated connection from the pool.","commonSituations":"A consumer loop started before the subscription call completes; refactoring that reorders subscribe() after the read loop; tests that call parse_response directly to inspect raw frames.","solutions":["Call `await pubsub.subscribe(channel)` (or psubscribe) before invoking parse_response/get_message.","Use get_message(timeout=...) which is the intended public API and is only entered after subscribing.","Guard the read path: check `pubsub.connection is not None` or `pubsub.subscribed` before reading."],"exampleFix":"// before\npubsub = r.pubsub()\nresp = await pubsub.parse_response()\n// after\npubsub = r.pubsub()\nawait pubsub.subscribe(\"ch\")\nresp = await pubsub.parse_response()","handlingStrategy":"validation","validationCode":"pubsub = r.pubsub()\nawait pubsub.subscribe('ch')\nassert pubsub.connection is not None\nresp = await pubsub.parse_response()","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always call subscribe()/psubscribe() before any read.","Prefer the higher-level get_message(timeout=...) over parse_response().","Start worker tasks only after subscription completes."],"tags":["redis","asyncio","pubsub","api-misuse","connection-state"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}