redis/redis-py · error · TimeoutError

Timeout reading from socket

Error message

Timeout reading from socket

What it means

Raised by SocketBuffer._read_from_socket when a non-blocking recv (BlockingIOError/SSLWantReadError, matching errno) occurs with timeout == 0. It surfaces as redis.exceptions.TimeoutError — a zero-timeout poll found no data and the caller asked to be notified.

Source

Thrown at redis/_parsers/socket.py:89

                if length is not None and length > marker:
                    continue
                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:
            buf.seek(current_pos)
            if custom_timeout:
                sock.settimeout(self.socket_timeout)

    def can_read(self, timeout: float = 0) -> bool:
        return bool(self.unread_bytes()) or self._read_from_socket(
            timeout=timeout, raise_on_timeout=False
        )

    def read(self, length: int, timeout: Union[float, object] = SENTINEL) -> bytes:
        length = length + 2  # make sure to read the \r\n terminator
        # BufferIO will return less than requested if buffer is short
        data = self._buffer.read(length)
        missing = length - len(data)
        if missing:
            # fill up the buffer and read the remainder

View on GitHub (pinned to 43bf5ac31a)

Solutions

  1. Use a small positive socket_timeout (e.g. 0.5s).
  2. Pass an explicit positive timeout to pubsub.get_message().
  3. Catch redis.TimeoutError and retry with backoff.
  4. Scale Redis if it's genuinely too slow to respond.

Example fix

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

Strategy: retry

Validate before calling

if socket_timeout == 0:
    raise ValueError('use a positive socket_timeout')
r = redis.Redis(host=host, socket_timeout=socket_timeout)

Type guard

def is_socket_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: can_read()/pubsub poll/health check with socket_timeout=0 against a busy server or a TLS connection whose plaintext isn't ready within the zero window.

Common situations: Setting socket_timeout=0; tight pubsub.get_message(timeout=0) loops on slow links; TLS yielding SSLWantReadError before handshake; overloaded single-threaded Redis.

Understand the failure class

Related errors


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