redis/redis-py · error · PubSubError

A non health check response was cleaned by execute_command:

Error message

A non health check response was cleaned by execute_command: {response}

What it means

Raised in `PubSub.clean_health_check_responses` while draining queued health-check PING replies. The client periodically sends `PING <health-check-message>` to keep the pubsub socket alive; when it later drains those replies it expects every consumed frame to be the matching health-check response. If a frame is consumed that is NOT a health-check reply, a `PubSubError` is raised because the socket's framing has desynchronized and continuing would corrupt the message stream.

Source

Thrown at redis/client.py:1247

        kwargs = {"check_health": not self.subscribed}
        if not self.subscribed:
            self.clean_health_check_responses()
        with self._lock:
            self._execute(connection, connection.send_command, *args, **kwargs)

    def clean_health_check_responses(self) -> None:
        """
        If any health check responses are present, clean them
        """
        ttl = 10
        conn = self.connection
        while conn and self.health_check_response_counter > 0 and ttl > 0:
            if self._execute(conn, conn.can_read, timeout=conn.socket_timeout):
                response = self._execute(conn, conn.read_response)
                if self.is_health_check_response(response):
                    self.health_check_response_counter -= 1
                else:
                    raise PubSubError(
                        "A non health check response was cleaned by "
                        "execute_command: {}".format(response)
                    )
            ttl -= 1

    def _reconnect(
        self,
        conn,
        error: Optional[Exception] = None,
        failure_count: Optional[int] = None,
        start_time: Optional[float] = None,
        command_name: Optional[str] = None,
    ) -> None:
        """
        The supported exceptions are already checked in the
        retry object so we don't need to do it here.

        In this error handler we are trying to reconnect to the server.

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Ensure the PubSub connection is used exclusively for pubsub (never share it with normal command traffic) — call `pubsub = client.pubsub()` and only use pubsub methods on it.
  2. If using RESP3, configure a proper push handler (`push_handler_func`) so push notifications are routed correctly and do not sit on the response stream.
  3. Recreate the PubSub object and re-subscribe after the error — the connection state is corrupted and cannot be recovered in place.
  4. Review `health_check_interval` and `socket_timeout`; if health checks fire faster than the consumer drains them, raise the interval or ensure `get_message()` is polled frequently.

Example fix

# before
ps = client.pubsub()
ps.subscribe('ch')
# same client used elsewhere -> interleaved traffic

# after
ps = client.pubsub()
ps.subscribe('ch')
for msg in ps.listen():
    handle(msg)  # drain promptly, keep this connection pubsub-only
Defensive patterns

Strategy: try-catch

Try / catch

from redis.exceptions import PubSubError
try:
    msg = ps.get_message(timeout=1.0)
except PubSubError:
    # connection framing is corrupted — recreate pubsub and re-subscribe
    ps.close()
    ps = client.pubsub()
    ps.subscribe('ch')

Prevention

When it happens

Trigger: A PubSub instance with `health_check_interval` configured loses ordering between the health-check PING and other pubsub traffic — typically because the connection was shared or reused, a server-pushed message arrived interleaved with the PING reply, the connection dropped and reconnected mid-drain, or a RESP3 push notification was mistaken for a reply. The loop (ttl=10) drains up to 10 frames and raises on the first non-health-check frame.

Common situations: Long-lived pubsub listeners on unstable networks where reconnects race with health checks; RESP3 mode with push handlers enabled; mixed usage of the same connection for pubsub and normal commands; version changes that altered push/health-check framing.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/03998d9e4dd1fccc.json. Report an issue: GitHub.