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 by PubSub.clean_health_check_responses() when, while draining queued socket responses that were expected to be health-check PING replies, the library reads a response that is NOT a recognized health-check response. It indicates the pubsub connection's response stream is out of sync with the library's bookkeeping (health_check_response_counter), so a real pubsub message or unexpected protocol frame was consumed as if it were a health check.

Solutions

  1. Avoid issuing direct commands on a PubSub object that is actively subscribed; use a separate client for command traffic.
  2. If you must send commands, ensure no health-check PINGs are in flight (raise health_check_interval or call check_health at controlled points).
  3. Upgrade redis-py to the latest patch release — response-stream desync bugs in this drain loop have been fixed over time.
  4. If reproducing, capture the exact `response` value in the error message to identify which non-health-check frame is being read.
  5. As a last resort, lower socket_timeout or disable health_check_interval (set to 0) on the connection used for pubsub.

Example fix

// before
pubsub = r.pubsub()
pubsub.subscribe('ch')
pubsub.execute_command('GET', 'key')  # interleaves with health checks

// after
pubsub = r.pubsub()
pubsub.subscribe('ch')
# use a separate client for command traffic
value = r.get('key')
Defensive patterns

Strategy: try-catch

Validate before calling

# Before issuing any command on a pubsub connection, confirm no health-check
# responses are pending and the connection is subscribed cleanly.
if pubsub.health_check_response_counter > 0:
    pubsub.clean_health_check_responses()  # may raise PubSubError
# Prefer not to share the pubsub connection for command traffic at all.

Type guard

def is_safe_to_send_on_pubsub(pubsub) -> bool:
    return (
        pubsub.connection is not None
        and pubsub.health_check_response_counter == 0
    )

Try / catch

from redis.exceptions import PubSubError
try:
    pubsub.clean_health_check_responses()
except PubSubError as e:
    # response stream is desynced; reconnect and resubscribe
    pubsub.close()
    pubsub = client.pubsub()
    pubsub.subscribe('channel')

Prevention

When it happens

Trigger: Calling PubSub.execute_command (or any command sent over a subscribed pubsub connection) while health_check_response_counter > 0, or interleaving direct commands with pending health-check PINGs on a subscribed connection. Concretely: a subscribed PubSub where conn.health_check_interval is set and a real message arrives between PING send and the clean_health_check_responses() drain loop in _execute.

Common situations: A long-lived pubsub listener with a low health_check_interval under heavy message load; sending raw commands on a PubSub object that is also receiving messages; RESP2/RESP3 protocol mismatches that change the shape of the PING reply; bugs in custom retry logic that re-issue PINGs.

Related errors


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

Appendix: 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 6a6b581b48)