redis/redis-py · error · ConnectionError
Connection closed by server.
Error message
Connection closed by server.
What it means
Raised by the sync pure-Python RESP2 parser _read_response when SocketBuffer.readline() returns empty: the buffer hit EOF because the server closed the socket (the underlying recv in SocketBuffer._read_from_socket returned b'', error 36). This is the RESP2 (protocol=2) path's 'Connection closed by server.' and the pure-Python equivalent of the hiredis error 20.
Solutions
- Configure retry_on_error=[ConnectionError, TimeoutError] + Retry/backoff.
- Enable health_check_interval and socket_keepalive.
- Raise the redis 'timeout' to exceed your longest blocking command.
- Catch redis.exceptions.ConnectionError and reconnect/retry.
Example fix
# before
r = redis.Redis(protocol=2) # pure-Python RESP2 path
r.get('k') # after server restart -> 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(
protocol=2, health_check_interval=30, socket_keepalive=True,
retry_on_error=[ConnectionError, TimeoutError],
retry=Retry(ExponentialWithJitterBackoff(), 3),
)
r.get('k') Defensive patterns
Strategy: retry
Validate before calling
# Liveness probe before critical work (pure-Python RESP2 client)
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 resp2_server_closed(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 (health_check_interval > 0) catch stale connections before your command does.
When it happens
Trigger: Any sync command over a protocol=2 connection whose reply is interrupted by a server-side close: restart, failover, CLIENT KILL, idle timeout, eviction, network drop. The readline loop (socket.py:112-118) gets b'' and propagates EOF up as an empty 'raw' at resp2.py:33-34.
Common situations: Forced protocol=2 (or an older default) on a long-lived connection behind an aggressive idle reaper; Redis failover; RDB save under memory pressure causing the server to drop clients; a misconfigured 'timeout' in redis.conf.
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.
- Bad response from PING health check
- Connection closed by server.
- Connection closed by server.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/658bd2d41ab8aa10.
Report an issue: GitHub.
Appendix: source
Thrown at redis/_parsers/resp2.py:34
pos = self._buffer.get_pos() if self._buffer else None
try:
result = self._read_response(
disable_decoding=disable_decoding, timeout=timeout
)
except BaseException:
if self._buffer:
self._buffer.rewind(pos)
raise
else:
self._buffer.purge()
return result
def _read_response(
self, disable_decoding=False, timeout: Union[float, object] = SENTINEL
):
raw = self._buffer.readline(timeout=timeout)
if not raw:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
byte, response = raw[:1], raw[1:]
# server returned an error
if byte == b"-":
response = response.decode("utf-8", errors="replace")
error = self.parse_error(response)
# if the error is a ConnectionError, raise immediately so the user
# is notified
if isinstance(error, ConnectionError):
raise error
# otherwise, we're dealing with a ResponseError that might belong
# inside a pipeline response. the connection's read_response()
# and/or the pipeline's execute() will raise this error if
# necessary, so just return the exception instance here.
return error
# single value
elif byte == b"+":View on GitHub (pinned to 6a6b581b48)