redis/redis-py · error · ConnectionError

Bad response from PING health check

Error message

Bad response from PING health check

What it means

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.

Solutions

  1. Set socket_keepalive=True and a sensible socket_timeout to detect dead sockets earlier.
  2. Reduce health_check_interval to catch bad connections faster.
  3. Ensure nothing but Redis is answering on the target host:port (remove HTTP/TLS-terminating proxies on the Redis port).
  4. Configure retry_on_timeout=True / a Retry policy so transient corruption triggers reconnect.
  5. Investigate RESP desync: enable debug logging of the parser and check for earlier unhandled responses.

Example fix

# before
r = redis.Redis(host=h, port=p)
# after
r = redis.Redis(
    host=h, port=p,
    health_check_interval=30,
    socket_keepalive=True,
    socket_timeout=5,
    retry_on_timeout=True,
)
Defensive patterns

Strategy: retry

Validate before calling

# Configure resilient health-check defaults up front
r = redis.Redis(
    host=h, port=p,
    health_check_interval=30,   # detect dead sockets
    socket_keepalive=True,
    socket_timeout=5,
    retry_on_timeout=True,
    retry=Retry(ExponentialBackoff(), 3),
)

Type guard

null

Try / catch

from redis.exceptions import ConnectionError
for _ in range(3):
    try:
        r.get('k')
        break
    except ConnectionError as e:
        if 'PING health check' in str(e):
            continue  # pool reopens; retry idempotent op
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/c338869636befef1. Report an issue: GitHub.

Appendix: source

Thrown at redis/connection.py:1321

            self.maintenance_state = MaintenanceState.NONE
            # reset the sets that keep track of received start maint
            # notifications and skipped end maint notifications
            self.reset_received_notifications()

    def mark_for_reconnect(self):
        self._should_reconnect = True

    def should_reconnect(self):
        return self._should_reconnect

    def reset_should_reconnect(self):
        self._should_reconnect = False

    def _send_ping(self):
        """Send PING, expect PONG in return"""
        self.send_command("PING", check_health=False)
        if str_if_bytes(self.read_response()) != "PONG":
            raise ConnectionError("Bad response from PING health check")

    def _ping_failed(self, error, failure_count):
        """Function to call when PING fails"""
        self.disconnect(
            error=error, failure_count=failure_count, health_check_failed=True
        )

    def check_health(self):
        """Check the health of the connection with a PING/PONG"""
        if self.health_check_interval and time.monotonic() > self.next_health_check:
            self.retry.call_with_retry(
                self._send_ping,
                self._ping_failed,
                with_failure_count=True,
            )

    def send_packed_command(self, command, check_health=True):
        """Send an already packed command to the Redis server"""

View on GitHub (pinned to 6a6b581b48)