{"record":{"id":"9ad1ed7c8be59a33","repo":"redis/redis-py","slug":"timeout-reading-from-socket","errorCode":null,"errorMessage":"Timeout reading from socket","messagePattern":"Timeout reading from socket","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"redis/_parsers/hiredis.py","lineNumber":213,"sourceCode":"            reader.feed(self._buffer, 0, bufflen)\n            # data was read from the socket and added to the buffer.\n            # return True to indicate that data was read.\n            return True\n        except socket.timeout:\n            if raise_on_timeout:\n                raise TimeoutError(\"Timeout reading from socket\")\n            return False\n        except NONBLOCKING_EXCEPTIONS as ex:\n            # if we're in nonblocking mode and the recv raises a\n            # blocking error, simply return False indicating that\n            # there's no data to be read. otherwise raise the\n            # original exception.\n            allowed = NONBLOCKING_EXCEPTION_ERROR_NUMBERS.get(ex.__class__, -1)\n            if ex.errno == allowed:\n                if not raise_on_timeout:\n                    return False\n                if timeout == 0:\n                    raise TimeoutError(\"Timeout reading from socket\")\n            raise ConnectionError(f\"Error while reading from socket: {ex.args}\")\n        finally:\n            if custom_timeout:\n                sock.settimeout(self._socket_timeout)\n\n    def read_response(\n        self,\n        disable_decoding=False,\n        push_request=False,\n        timeout: Union[float, object] = SENTINEL,\n    ):\n        # Bind the reader locally so a concurrent disconnect that clears\n        # self._reader can't turn a later .gets() into an AttributeError;\n        # re-checking the attribute each time would still race.\n        reader = self._reader\n        if reader is None:\n            raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)\n","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/redis/redis-py/blob/43bf5ac31a5d7538fad3b1928e717ba757048041/redis/_parsers/hiredis.py#L195-L231","documentation":"Raised by the sync hiredis parser's read_from_socket when a non-blocking recv (BlockingIOError/SSLWantReadError with matching errno) occurs with timeout == 0 and raise_on_timeout is True. It surfaces as redis.exceptions.TimeoutError because a zero-timeout poll found no data and the caller asked to be told.","triggerScenarios":"Calling can_read()/health-check/pubsub poll with socket_timeout=0, or a read against a busy server / not-yet-ready TLS handshake where plaintext isn't available within a zero-length window.","commonSituations":"Setting `socket_timeout=0` thinking it means 'no timeout'; pubsub.get_message(timeout=0) loops on slow links; TLS connections that yield SSLWantReadError before the handshake completes; very busy single-threaded Redis blocking the read.","solutions":["Use a small positive socket_timeout (e.g. 0.5s) instead of 0.","For pubsub polls, pass an explicit positive timeout to get_message() rather than relying on socket_timeout=0.","Catch redis.TimeoutError and retry with backoff; treat it as transient.","Scale/shard Redis if the server is genuinely too busy to respond in time."],"exampleFix":"# before\nr = redis.Redis(host='redis', socket_timeout=0)\nr.get('k')\n# after\nr = redis.Redis(host='redis', socket_timeout=0.5)\nr.get('k')","handlingStrategy":"retry","validationCode":"# Reject a zero socket_timeout before constructing the client.\nif socket_timeout == 0:\n    raise ValueError('socket_timeout=0 forces zero-timeout reads; use a small positive value')\nr = redis.Redis(host=host, socket_timeout=socket_timeout)","typeGuard":"def is_zero_timeout(exc: Exception) -> bool:\n    from redis.exceptions import TimeoutError\n    return isinstance(exc, TimeoutError) and 'Timeout reading from socket' in str(exc)","tryCatchPattern":"from redis.exceptions import TimeoutError\nimport time\nfor backoff in (0.1, 0.2, 0.4):\n    try:\n        return r.get('k')\n    except TimeoutError:\n        time.sleep(backoff)\nraise TimeoutError('redis read timed out after retries')","preventionTips":["Never set socket_timeout=0 in production.","Give pubsub polls a real timeout.","Distinguish transient TimeoutError from hard failures in your retry policy."],"tags":["network","timeout","sync","hiredis"],"analyzedSha":"43bf5ac31a5d7538fad3b1928e717ba757048041","analyzedAt":"2026-08-06T22:35:38.048Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}