redis/redis-py · error · ConnectionError
Connection closed by server.
Error message
Connection closed by server.
What it means
The lowest-level read: SocketBuffer._read_from_socket raises redis.exceptions.ConnectionError when sock.recv() returns empty bytes (b'') - the OS-level signal that the peer closed the TCP connection. This is where every 'Connection closed by server.' in the pure-Python parsers originates; the RESP2/RESP3 readline EOF (errors 28/32) ultimately traces here (socket.py:66-67).
Solutions
- Configure retry_on_error=[ConnectionError, TimeoutError] + Retry/backoff.
- Enable health_check_interval and socket_keepalive.
- Set socket_timeout larger than any blocking-command block time.
- Catch redis.exceptions.ConnectionError and reconnect/retry.
Example fix
# before
r = redis.Redis(parser_class=redis.connection.DefaultParser) # pure-Python, no retry
r.get('k') # server closed -> ConnectionError: Connection closed by server.
# after
from redis.retry import Retry
from redis.backoff import ExponentialWithJitterBackoff
from redis.exceptions import ConnectionError, TimeoutError
r = redis.Redis(
health_check_interval=30, socket_keepalive=True, socket_timeout=5,
retry_on_error=[ConnectionError, TimeoutError],
retry=Retry(ExponentialWithJitterBackoff(), 3),
)
r.get('k') Defensive patterns
Strategy: retry
Validate before calling
from redis.exceptions import ConnectionError
def alive(r):
try:
r.ping()
return True
except ConnectionError:
return False Type guard
from redis.exceptions import ConnectionError as RCE
def is_socket_eof(e: BaseException) -> bool:
return isinstance(e, RCE) and 'closed by server' in str(e).lower() Try / catch
from redis.exceptions import ConnectionError, TimeoutError
try:
r.get('k')
except (ConnectionError, TimeoutError):
r.get('k') Prevention
- redis.exceptions.ConnectionError does not subclass the builtin - catch the redis class.
- Health checks catch stale connections before your command does.
When it happens
Trigger: Any sync read path on a pure-Python (non-hiredis) connection whose peer has closed: restart, failover, CLIENT KILL, idle timeout, eviction, network drop, proxy reaper. recv() returning b'' is the precise trigger.
Common situations: Pure-Python parser (hiredis not installed/used) on a long-lived connection behind an idle reaper; Redis failover; server under memory pressure dropping clients; misconfigured 'timeout'.
Understand the failure class
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- Connection closed by server.
- Connection closed by server.
- Timeout reading from socket
- Bad response from PING health check
- Connection closed by server.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/6db4f9fbae128bc0.
Report an issue: GitHub.
Appendix: source
Thrown at redis/_parsers/socket.py:67
timeout: Union[float, object] = SENTINEL,
raise_on_timeout: Optional[bool] = True,
) -> bool:
sock = self._sock
socket_read_size = self.socket_read_size
marker = 0
custom_timeout = timeout is not SENTINEL
buf = self._buffer
current_pos = buf.tell()
buf.seek(0, SEEK_END)
if custom_timeout:
sock.settimeout(timeout)
try:
while True:
data = sock.recv(socket_read_size)
# an empty string indicates the server shutdown the socket
if isinstance(data, bytes) and len(data) == 0:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
buf.write(data)
data_length = len(data)
marker += data_length
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:View on GitHub (pinned to 6a6b581b48)