redis/redis-py · error · ConnectionError
Connection closed by server.
Error message
Connection closed by server.
What it means
Raised by the sync RESP3 parser _read_response when SocketBuffer.readline() returns empty: the server closed the socket (recv returned b''). RESP3 (protocol=3, the current default on the wire) path's 'Connection closed by server.' and the RESP3 equivalent of errors 28/36.
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() # protocol=3 is the default; no retry
r.get('k') # after a 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(
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 resp3_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=3 connection whose reply is interrupted by a server-side close: restart, failover, CLIENT KILL, idle timeout, maxmemory-clients eviction, network drop.
Common situations: Default RESP3 client on a long-lived connection behind an aggressive idle reaper; failover of a managed Redis; RDB save under memory pressure dropping 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/e52ab68fadd77563.
Report an issue: GitHub.
Appendix: source
Thrown at redis/_parsers/resp3.py:67
else:
if self._buffer is not None:
try:
self._buffer.purge()
except AttributeError:
# Buffer may have been set to None by another thread after
# the check above; result is still valid so we don't raise
pass
return result
def _read_response(
self,
disable_decoding=False,
push_request=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 in (b"-", b"!"):
if byte == b"!":
response = self._buffer.read(int(response), timeout=timeout)
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 errorView on GitHub (pinned to 6a6b581b48)