redis/redis-py · error · TimeoutError
Timeout reading from socket
Error message
Timeout reading from socket
What it means
Raised by the sync hiredis parser read_from_socket when socket.recv_into() raises socket.timeout because no bytes arrived within the active socket timeout (the connection's socket_timeout, or a per-call timeout passed via read_from_socket(timeout=)). It is a redis.exceptions.TimeoutError (error_type=NETWORK), which is distinct from Python's builtin TimeoutError and does not subclass it.
Solutions
- Raise socket_timeout to comfortably exceed the slowest expected command/block time.
- For blocking commands, keep their block argument below socket_timeout, or pass an explicit higher per-call timeout.
- Avoid KEYS/SMEMBERS in production; use SCAN and cursor pagination.
- Add retry with backoff for TimeoutError via retry_on_error=[TimeoutError].
- Profile long commands on the server (SLOWLOG GET) and optimize or remove them.
Example fix
# before
r = redis.Redis(socket_timeout=0.5)
r.blpop('q', timeout=10) # -> TimeoutError: Timeout reading from socket
# after - timeout covers the block window
r = redis.Redis(socket_timeout=12)
r.blpop('q', timeout=10) Defensive patterns
Strategy: retry
Validate before calling
# Verify socket_timeout can host your longest op before issuing it
def timeout_ok(r, block_seconds):
st = r.connection_pool.connection_kwargs.get('socket_timeout')
return st is None or st > block_seconds Type guard
from redis.exceptions import TimeoutError as RedisTimeoutError
def is_redis_socket_timeout(e: BaseException) -> bool:
return isinstance(e, RedisTimeoutError) and str(e) == 'Timeout reading from socket' Try / catch
from redis.exceptions import TimeoutError
import time
for attempt in range(3):
try:
return r.get('k')
except TimeoutError:
if attempt == 2:
raise
time.sleep(0.2 * (2 ** attempt)) Prevention
- Set socket_timeout strictly greater than any BLOCK time passed to BLPOP/BZPOPMIN/XREAD.
- Don't catch the builtin TimeoutError - redis raises redis.exceptions.TimeoutError, which does not subclass it.
- Never run KEYS in production; its wall time is unbounded and will trip any finite socket_timeout.
When it happens
Trigger: A command whose reply takes longer to arrive than the timeout: KEYS * / SMEMBERS on a huge keyspace, large SORT, EVAL on a slow script, DEBUG SLEEP, or a blocking command (BLPOP/BZPOPMIN/XREAD BLOCK) whose block time exceeds socket_timeout. Also a congested network or a server stalled under load (RDB bgsave, AOF fsync=always stall).
Common situations: Default/low socket_timeout (e.g. 0.1s) against a loaded Redis; running KEYS in production; BLPOP with a timeout greater than the client socket_timeout; cross-region links with latency spikes; Redis blocked on disk I/O during AOF fsync.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timeout reading from socket
- Timeout reading from
- Connection closed by server.
- Connection closed by server.
- Connection closed by server.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/9ad1ed7c8be59a33.
Report an issue: GitHub.
Appendix: source
Thrown at redis/_parsers/hiredis.py:201
# a shared client closed via `with redis:`); on_disconnect() sets both
# _sock and _reader to None. Bind them locally and fail with a
# descriptive, retryable ConnectionError instead of an AttributeError.
if sock is None or reader is None:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
custom_timeout = timeout is not SENTINEL
try:
if custom_timeout:
sock.settimeout(timeout)
bufflen = sock.recv_into(self._buffer)
if bufflen == 0:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
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(View on GitHub (pinned to 6a6b581b48)