{"record":{"id":"658bd2d41ab8aa10","repo":"redis/redis-py","slug":"connection-closed-by-server-658bd2","errorCode":null,"errorMessage":"Connection closed by server.","messagePattern":"Connection closed by server\\.","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"redis/_parsers/resp2.py","lineNumber":34,"sourceCode":"        pos = self._buffer.get_pos() if self._buffer else None\n        try:\n            result = self._read_response(\n                disable_decoding=disable_decoding, timeout=timeout\n            )\n        except BaseException:\n            if self._buffer:\n                self._buffer.rewind(pos)\n            raise\n        else:\n            self._buffer.purge()\n            return result\n\n    def _read_response(\n        self, disable_decoding=False, timeout: Union[float, object] = SENTINEL\n    ):\n        raw = self._buffer.readline(timeout=timeout)\n        if not raw:\n            raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)\n\n        byte, response = raw[:1], raw[1:]\n\n        # server returned an error\n        if byte == b\"-\":\n            response = response.decode(\"utf-8\", errors=\"replace\")\n            error = self.parse_error(response)\n            # if the error is a ConnectionError, raise immediately so the user\n            # is notified\n            if isinstance(error, ConnectionError):\n                raise error\n            # otherwise, we're dealing with a ResponseError that might belong\n            # inside a pipeline response. the connection's read_response()\n            # and/or the pipeline's execute() will raise this error if\n            # necessary, so just return the exception instance here.\n            return error\n        # single value\n        elif byte == b\"+\":","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/redis/redis-py/blob/43bf5ac31a5d7538fad3b1928e717ba757048041/redis/_parsers/resp2.py#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"Same family as other server-close errors — managed Redis/proxies reaping idle flows, rolling deploys, failover, maxmemory-clients eviction.","solutions":["Enable health_check_interval and retry_on_error=[ConnectionError, TimeoutError].","Set socket_keepalive=True.","Tune Redis `timeout` to exceed your pool's idle window.","Catch ConnectionError and retry on a fresh connection."],"exampleFix":"# before\nr = redis.Redis(host='redis')\nr.get('k')\n# after\nr = redis.Redis(host='redis', health_check_interval=30,\n                socket_keepalive=True,\n                retry_on_error=[redis.ConnectionError, redis.TimeoutError])\nr.get('k')","handlingStrategy":"retry","validationCode":"# Probe liveness before a critical command.\ntry:\n    assert r.ping()\nexcept redis.ConnectionError:\n    r.close(); r = redis.Redis(...)\nr.get('k')","typeGuard":"def is_closed_error(exc: Exception) -> bool:\n    from redis.exceptions import ConnectionError\n    return isinstance(exc, ConnectionError) and 'closed by server' in str(exc)","tryCatchPattern":"from redis.exceptions import ConnectionError\ntry:\n    return r.get('k')\nexcept ConnectionError:\n    r = redis.Redis(...)\n    return r.get('k')","preventionTips":["Always set health_check_interval in production.","Enable retry_on_error for transient network errors.","Keep socket_keepalive on across NAT/LB hops."],"tags":["network","connection","sync","resp2"],"analyzedSha":"43bf5ac31a5d7538fad3b1928e717ba757048041","analyzedAt":"2026-08-06T22:35:38.048Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}