{"record":{"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/6a6b581b48225afa0b76912d1028c6035baee932/redis/connection.py#L1303-L1339","documentation":"Raised by _send_ping (connection.py:1317-1321) during a periodic health check when PING is sent but the response is not 'PONG'. This indicates the connection is in a corrupt/half-open state where data can still be read but it is not a valid Redis reply (e.g. mid-protocol garbage, a proxy returning an HTTP error, or a connection that returned an unexpected frame). check_health() runs it through retry.call_with_retry; on final failure _ping_failed disconnects with health_check_failed=True.","triggerScenarios":"health_check_interval is set (>0) and the established socket returns something other than PONG to PING — corrupted buffer, an intermediary returning an error page, a stale connection after a silent server-side close, or a protocol desync from a prior malformed exchange.","commonSituations":"Long-idle connections behind NAT/firewalls that silently drop; a proxy returning a 502/HTML body on the Redis port; RESP parser desync after an earlier unhandled error; network equipment mangling the byte stream.","solutions":["Set socket_keepalive=True and a sensible socket_timeout to detect dead sockets earlier.","Reduce health_check_interval to catch bad connections faster.","Ensure nothing but Redis is answering on the target host:port (remove HTTP/TLS-terminating proxies on the Redis port).","Configure retry_on_timeout=True / a Retry policy so transient corruption triggers reconnect.","Investigate RESP desync: enable debug logging of the parser and check for earlier unhandled responses."],"exampleFix":"# before\nr = redis.Redis(host=h, port=p)\n# after\nr = redis.Redis(\n    host=h, port=p,\n    health_check_interval=30,\n    socket_keepalive=True,\n    socket_timeout=5,\n    retry_on_timeout=True,\n)","handlingStrategy":"retry","validationCode":"# Configure resilient health-check defaults up front\nr = redis.Redis(\n    host=h, port=p,\n    health_check_interval=30,   # detect dead sockets\n    socket_keepalive=True,\n    socket_timeout=5,\n    retry_on_timeout=True,\n    retry=Retry(ExponentialBackoff(), 3),\n)","typeGuard":"null","tryCatchPattern":"from redis.exceptions import ConnectionError\nfor _ in range(3):\n    try:\n        r.get('k')\n        break\n    except ConnectionError as e:\n        if 'PING health check' in str(e):\n            continue  # pool reopens; retry idempotent op\n        raise","preventionTips":["Always set health_check_interval + socket_keepalive for long-lived clients.","Confirm nothing but Redis answers on the port (no HTTP/TLS proxies).","Use the connection pool so bad sockets are replaced automatically.","Investigate RESP desync if PONG corruption recurs."],"tags":["health-check","connection","network","resilience"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}