{"id":"eaaf6e2f240ac267","repo":"redis/redis-py","slug":"error-while-reading-from-host-error-e-args-eaaf6e","errorCode":null,"errorMessage":"Error while reading from {host_error}: {e.args}","messagePattern":"Error while reading from (.+?): (.+?)","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"redis/connection.py","lineNumber":1391,"sourceCode":"            check_health=kwargs.get(\"check_health\", True),\n        )\n\n    def can_read(self, timeout: float = 0) -> bool:\n        \"\"\"Poll the socket to see if there's data that can be read.\"\"\"\n        # TODO: Rename this API; it detects pending data or dirty/closed\n        # connection state, not only whether application data can be read.\n        sock = self._sock\n        if not sock:\n            self.connect()\n\n        host_error = self._host_error()\n\n        try:\n            return self._parser.can_read(timeout)\n\n        except OSError as e:\n            self.disconnect()\n            raise ConnectionError(f\"Error while reading from {host_error}: {e.args}\")\n\n    def read_response(\n        self,\n        disable_decoding=False,\n        *,\n        timeout: Union[float, object] = SENTINEL,\n        disconnect_on_error=True,\n        push_request=False,\n    ):\n        \"\"\"Read the response from a previously sent command\"\"\"\n\n        host_error = self._host_error()\n\n        try:\n            if self.protocol in [\"3\", 3]:\n                response = self._parser.read_response(\n                    disable_decoding=disable_decoding,\n                    push_request=push_request,","sourceCodeStart":1373,"sourceCodeEnd":1409,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/connection.py#L1373-L1409","documentation":"Raised as a ConnectionError in can_read() when an OSError occurs while polling the parser/socket for pending data. The connection is disconnected and the OS error args are included. can_read is used to detect pending data (e.g. for pubsub invalidation drains) before a blocking read.","triggerScenarios":"Calling can_read() (used by pubsub get_message, client-side caching invalidation processing, and health probing) on a socket that raises OSError, e.g. the peer reset the connection between commands. The error embeds host_error and e.args.","commonSituations":"Pubsub subscriber whose connection was killed by the server; client-side caching draining invalidations on a dead socket; idle connection dropped by a NAT then polled; forked process using a stale socket.","solutions":["Catch ConnectionError around pubsub/invalidation loops and reconnect.","Ensure health_check_interval is set so dead connections are detected proactively.","Avoid sharing connections across forked processes; create a new client after fork.","Inspect e.args for the OS errno to diagnose reset vs. timeout vs. unreachable."],"exampleFix":"// before\nmsg = pubsub.get_message()\n// after\ntry:\n    msg = pubsub.get_message()\nexcept redis.ConnectionError:\n    pubsub.reset()\n    msg = pubsub.get_message()","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    msg = pubsub.get_message()\nexcept redis.exceptions.ConnectionError as e:\n    if 'while reading from' in str(e):\n        pubsub.reset()\n        msg = pubsub.get_message()","preventionTips":["Wrap pubsub/invalidation polling in try/except and reconnect on ConnectionError.","Set health_check_interval to prune dead connections.","Do not share connections across forked processes."],"tags":["network","pubsub","read","connection-reset"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}