redis/redis-py · error · TimeoutError
Timeout reading from
Error message
Timeout reading from {host_error} What it means
Raised as TimeoutError from read_response() when the read_timeout (self.socket_timeout, or an explicit per-call timeout that is None) elapses before the parser produces a response. Only raised when the user did NOT pass an explicit timeout; passing an explicit timeout that elapses returns None instead (the operation is retried). The connection is disconnected nowait before raising.
Solutions
- Raise socket_timeout to exceed the longest legitimate blocking command.
- For blocking commands, pass an explicit timeout= to read_response()/parse_response() so you get None instead of an exception.
- Investigate server slowlog, AOF/fsync latency, and fork latency (INFO stats, LATENCY events).
- Use command_timeout or per-command timeouts instead of a single global socket_timeout when workloads vary.
Example fix
// before
r = redis.asyncio.Redis(host=h, socket_timeout=1.0)
v = await r.blpop('q', timeout=10) # always times out the socket first
// after
r = redis.asyncio.Redis(host=h) # no socket_timeout
v = await r.blpop('q', timeout=10) Defensive patterns
Strategy: try-catch
Validate before calling
def socket_timeout_for_block(block_seconds: float) -> float | None:
# don't set a socket_timeout smaller than the longest blocking wait
return None if block_seconds > 0 else 5.0 Type guard
def is_read_timeout(exc: BaseException) -> bool:
return isinstance(exc, TimeoutError) and 'reading from' in str(exc).lower() Try / catch
from redis.retry import Retry
from redis.backoff import ExponentialBackoff
r = redis.asyncio.Redis(
host=h,
socket_timeout=5.0,
retry=Retry(ExponentialBackoff(), 2),
retry_on_timeout=True,
) Prevention
- Do not set socket_timeout below your longest blocking-command wait.
- Pass explicit timeout= to read_response() for blocking commands (returns None instead).
- Monitor server slowlog and fork/fsync latency.
When it happens
Trigger: Any await of a response (command read, pubsub poll, BLPOP-style blocking command) when socket_timeout is set and the server has not replied in time. Distinct from a blocking-command wait: this is the socket-level budget, and it kills the connection.
Common situations: socket_timeout smaller than a legitimate BLPOP/BRPOP/XREAD block duration; server stalled (slowlog, fork during save, AOF fsync); large response stuck behind head-of-line blocking; cross-region latency spikes.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Error while reading from
- Error while reading from
- Timeout writing to socket
- Timed out closing connection after
- Timeout reading from
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/67d1fda577b373ec.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/connection.py:1310
else:
async with timeout_context:
response = await self._read_response_from_parser(
disable_decoding=disable_decoding,
push_request=push_request,
)
else:
response = await self._read_response_from_parser(
disable_decoding=disable_decoding,
push_request=push_request,
)
except asyncio.TimeoutError:
if timeout is not None:
# user requested timeout, return None. Operation can be retried
return None
# it was a self.socket_timeout error.
if disconnect_on_error:
await self.disconnect(nowait=True)
raise TimeoutError(f"Timeout reading from {host_error}")
except OSError as e:
if disconnect_on_error:
await self.disconnect(nowait=True)
raise ConnectionError(f"Error while reading from {host_error} : {e.args}")
except BaseException:
# Also by default close in case of BaseException. A lot of code
# relies on this behaviour when doing Command/Response pairs.
# See #1128.
if disconnect_on_error:
await self.disconnect(nowait=True)
raise
if self.health_check_interval:
next_time = asyncio.get_running_loop().time() + self.health_check_interval
self.next_health_check = next_time
if isinstance(response, ResponseError):
raise response from NoneView on GitHub (pinned to 6a6b581b48)