redis/redis-py · error · TimeoutError

Timeout reading from socket

Error message

Timeout reading from socket

What it means

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.

Source

Thrown at redis/_parsers/hiredis.py:213

            reader.feed(self._buffer, 0, bufflen)
            # data was read from the socket and added to the buffer.
            # return True to indicate that data was read.
            return True
        except socket.timeout:
            if raise_on_timeout:
                raise TimeoutError("Timeout reading from socket")
            return False
        except NONBLOCKING_EXCEPTIONS as ex:
            # if we're in nonblocking mode and the recv raises a
            # blocking error, simply return False indicating that
            # there's no data to be read. otherwise raise the
            # original exception.
            allowed = NONBLOCKING_EXCEPTION_ERROR_NUMBERS.get(ex.__class__, -1)
            if ex.errno == allowed:
                if not raise_on_timeout:
                    return False
                if timeout == 0:
                    raise TimeoutError("Timeout reading from socket")
            raise ConnectionError(f"Error while reading from socket: {ex.args}")
        finally:
            if custom_timeout:
                sock.settimeout(self._socket_timeout)

    def read_response(
        self,
        disable_decoding=False,
        push_request=False,
        timeout: Union[float, object] = SENTINEL,
    ):
        # Bind the reader locally so a concurrent disconnect that clears
        # self._reader can't turn a later .gets() into an AttributeError;
        # re-checking the attribute each time would still race.
        reader = self._reader
        if reader is None:
            raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)

View on GitHub (pinned to 43bf5ac31a)

Solutions

  1. Use a small positive socket_timeout (e.g. 0.5s) instead of 0.
  2. For pubsub polls, pass an explicit positive timeout to get_message() rather than relying on socket_timeout=0.
  3. Catch redis.TimeoutError and retry with backoff; treat it as transient.
  4. Scale/shard Redis if the server is genuinely too busy to respond in time.

Example fix

# before
r = redis.Redis(host='redis', socket_timeout=0)
r.get('k')
# after
r = redis.Redis(host='redis', socket_timeout=0.5)
r.get('k')
Defensive patterns

Strategy: retry

Validate before calling

# Reject a zero socket_timeout before constructing the client.
if socket_timeout == 0:
    raise ValueError('socket_timeout=0 forces zero-timeout reads; use a small positive value')
r = redis.Redis(host=host, socket_timeout=socket_timeout)

Type guard

def is_zero_timeout(exc: Exception) -> bool:
    from redis.exceptions import TimeoutError
    return isinstance(exc, TimeoutError) and 'Timeout reading from socket' in str(exc)

Try / catch

from redis.exceptions import TimeoutError
import time
for backoff in (0.1, 0.2, 0.4):
    try:
        return r.get('k')
    except TimeoutError:
        time.sleep(backoff)
raise TimeoutError('redis read timed out after retries')

Prevention

When it happens

Trigger: 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.

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

Understand the failure class

Related errors


AI-assisted analysis of redis/redis-py@43bf5ac31a (2026-08-06). Data as JSON: /api/errors/9ad1ed7c8be59a33. Report an issue: GitHub.