redis/redis-py · error · ConnectionError

Connection closed by server.

Error message

Connection closed by server.

What it means

Raised by the shared SocketBuffer._read_from_socket (used by both sync pure-Python RESP2/RESP3 parsers) when sock.recv() returns b'' — the TCP EOF meaning the server closed the connection. It is the canonical server-close signal for the sync pure-Python path.

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 43bf5ac31a)

Solutions

  1. Enable health_check_interval and retry_on_error=[ConnectionError, TimeoutError].
  2. Set socket_keepalive=True.
  3. Tune Redis `timeout`.
  4. Catch ConnectionError and reconnect.

Example fix

# before
r = redis.Redis(host='redis')
r.get('k')
# after
r = redis.Redis(host='redis', health_check_interval=30,
                socket_keepalive=True,
                retry_on_error=[redis.ConnectionError, redis.TimeoutError])
Defensive patterns

Strategy: retry

Validate before calling

try:
    assert r.ping()
except redis.ConnectionError:
    r.close(); r = redis.Redis(...)
r.get('k')

Type guard

def is_closed_error(exc: Exception) -> bool:
    from redis.exceptions import ConnectionError
    return isinstance(exc, ConnectionError) and 'closed by server' in str(exc)

Try / catch

from redis.exceptions import ConnectionError
try:
    return r.get('k')
except ConnectionError:
    r = redis.Redis(...)
    return r.get('k')

Prevention

When it happens

Trigger: Any sync pure-Python parser read when the server half-closes the socket: restart, `timeout`, CLIENT KILL, failover, proxy idle drop.

Common situations: Managed Redis/proxies reaping idle flows; rolling deploys; failover; maxmemory-clients eviction.

Understand the failure class

Related errors


AI-assisted analysis of redis/redis-py@43bf5ac31a (2026-08-06). Data as JSON: /api/errors/6db4f9fbae128bc0. Report an issue: GitHub.