redis/redis-py · warning · ConnectionError

Error while reading from

Error message

Error while reading from {host_error}: {e.args}

What it means

Raised as ConnectionError from the deprecated can_read_destructive() when the parser's can_read() raises OSError. The host_error string comes from _host_error() (host:port for TCP, path for UDS). The connection is disconnected nowait before re-raising. This method is deprecated in favor of can_read().

Solutions

  1. Migrate to can_read() (can_read_destructive is deprecated since 8.0).
  2. Wrap the call in try/except ConnectionError and reconnect on failure.
  3. Ensure you are not probing a connection that was already disconnected.

Example fix

// before
if await conn.can_read_destructive():
    ...
// after
if await conn.can_read():
    ...
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

from redis.exceptions import ConnectionError

def is_can_read_error(exc: BaseException) -> bool:
    return isinstance(exc, ConnectionError) and 'reading from' in str(exc).lower()

Try / catch

from redis.exceptions import ConnectionError

try:
    ready = await conn.can_read_destructive()
except ConnectionError:
    conn = await pool.get_connection()
    ready = await conn.can_read()  # migrated off deprecated API

Prevention

When it happens

Trigger: Calling can_read_destructive() (deprecated, removed in 8.0) on a connection whose socket is already dead; the underlying asyncio reader hits OSError (EBADF/ECONNRESET) probing the buffer.

Common situations: Legacy code paths still calling the deprecated API; pubsub readiness checks after a server reset; testing harnesses probing connection state.

Related errors


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

Appendix: source

Thrown at redis/asyncio/connection.py:1228

            raise

    async def send_command(self, *args: Any, **kwargs: Any) -> None:
        """Pack and send a command to the Redis server"""
        await self.send_packed_command(
            self.pack_command(*args), check_health=kwargs.get("check_health", True)
        )

    @deprecated_function(
        version="8.0.0", reason="Use can_read() instead", name="can_read_destructive"
    )
    async def can_read_destructive(self) -> bool:
        """Check the socket to see if there's data loaded in the buffer."""
        try:
            return await self._parser.can_read()
        except OSError as e:
            await self.disconnect(nowait=True)
            host_error = self._host_error()
            raise ConnectionError(f"Error while reading from {host_error}: {e.args}")

    async def can_read(self) -> bool:
        """Check the socket to see if there's data loaded in the buffer."""
        # TODO: Rename this API; it detects pending data or dirty/closed
        # connection state, not only whether application data can be read.
        try:
            return await self._parser.can_read()
        except OSError as e:
            await self.disconnect(nowait=True)
            host_error = self._host_error()
            raise ConnectionError(f"Error while reading from {host_error}: {e.args}")

    async def read_response(
        self,
        disable_decoding: bool = False,
        timeout: float | None = None,
        *,
        disconnect_on_error: bool = True,

View on GitHub (pinned to 6a6b581b48)