{"id":"c338869636befef1","repo":"redis/redis-py","slug":"bad-response-from-ping-health-check-c33886","errorCode":null,"errorMessage":"Bad response from PING health check","messagePattern":"Bad response from PING health check","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"redis/connection.py","lineNumber":1321,"sourceCode":"            self.maintenance_state = MaintenanceState.NONE\n            # reset the sets that keep track of received start maint\n            # notifications and skipped end maint notifications\n            self.reset_received_notifications()\n\n    def mark_for_reconnect(self):\n        self._should_reconnect = True\n\n    def should_reconnect(self):\n        return self._should_reconnect\n\n    def reset_should_reconnect(self):\n        self._should_reconnect = False\n\n    def _send_ping(self):\n        \"\"\"Send PING, expect PONG in return\"\"\"\n        self.send_command(\"PING\", check_health=False)\n        if str_if_bytes(self.read_response()) != \"PONG\":\n            raise ConnectionError(\"Bad response from PING health check\")\n\n    def _ping_failed(self, error, failure_count):\n        \"\"\"Function to call when PING fails\"\"\"\n        self.disconnect(\n            error=error, failure_count=failure_count, health_check_failed=True\n        )\n\n    def check_health(self):\n        \"\"\"Check the health of the connection with a PING/PONG\"\"\"\n        if self.health_check_interval and time.monotonic() > self.next_health_check:\n            self.retry.call_with_retry(\n                self._send_ping,\n                self._ping_failed,\n                with_failure_count=True,\n            )\n\n    def send_packed_command(self, command, check_health=True):\n        \"\"\"Send an already packed command to the Redis server\"\"\"","sourceCodeStart":1303,"sourceCodeEnd":1339,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/connection.py#L1303-L1339","documentation":"Raised as a ConnectionError by _send_ping during a health check when the PING command's response is not 'PONG'. The socket is alive but the server returned an unexpected/garbled reply, indicating protocol corruption or a misbehaving intermediary. Health checks run periodically when health_check_interval is set.","triggerScenarios":"The periodic check_health() (gated by health_check_interval) calls _send_ping; if read_response() yields anything other than 'PONG', this fires. Common with a proxy returning an HTML error page, a connection pool handing back a poisoned/corrupted socket, or a RESP parsing desync.","commonSituations":"A misbehaving proxy/load balancer injecting non-Redis bytes; RESP parser desync after a malformed response; socket reused from a pool in a bad state; server under extreme memory pressure returning OOM-style replies on PING.","solutions":["Let the connection be discarded and retried (the client disconnects on this error).","Investigate any proxy/LB between client and server for non-Redis responses.","Reduce connection-pool reuse issues by lowering socket_timeout / health_check_interval.","Check server logs for OOM or protocol-level problems."],"exampleFix":"// before\nr = redis.Redis(host=h, health_check_interval=120)\n// after\nr = redis.Redis(host=h, health_check_interval=30)  # detect bad sockets sooner","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    r.set('k', 'v')\nexcept redis.exceptions.ConnectionError as e:\n    if 'PING health check' in str(e):\n        # poisoned socket discarded; retry on a fresh connection\n        r.set('k', 'v')","preventionTips":["Set a reasonable health_check_interval to evict bad sockets early.","Investigate proxies/LBs that may inject non-Redis bytes.","Avoid reusing connections across forked processes."],"tags":["health-check","connection","protocol-corruption"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}