redis/redis-py · error · ConnectionError

Connection closed by server.

Error message

Connection closed by server.

What it means

Raised by the sync RESP2 pure-Python parser when SocketBuffer.readline() returns empty — the server closed the connection before sending a complete reply line. It surfaces as redis.exceptions.ConnectionError so the caller reconnects.

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

Solutions

  1. Enable health_check_interval and retry_on_error=[ConnectionError, TimeoutError].
  2. Set socket_keepalive=True.
  3. Tune Redis `timeout` to exceed your pool's idle window.
  4. Catch ConnectionError and retry on a fresh connection.

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])
r.get('k')
Defensive patterns

Strategy: retry

Validate before calling

# Probe liveness before a critical command.
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 command via the pure-Python RESP2 parser when the server half-closes the socket: restart, `timeout`, CLIENT KILL, failover, proxy idle drop, or a truncated/malformed reply that drains the buffer to EOF.

Common situations: Same family as other server-close errors — 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/658bd2d41ab8aa10. Report an issue: GitHub.