redis/redis-py · error · ConnectionError

Error while reading from

Error message

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

What it means

Raised as ConnectionError from read_response() when the parser/reader raises OSError (not TimeoutError). Same path as the write-side OSError: the connection is disconnected nowait and re-raised with host_error and the OSError args. Note the message has a space before the colon, distinguishing it from the can_read variants.

Solutions

  1. Enable retry on ConnectionError with a bounded backoff for idempotent commands.
  2. Reduce response sizes or raise server client-output-buffer-limit to avoid mid-reply disconnects.
  3. Enable socket_keepalive to surface dead peers sooner.
  4. Verify the deployment is not running two clients on the same descriptor (no socket sharing across fork).

Example fix

// before
r = redis.asyncio.Redis(host=h)
// after
from redis.retry import Retry
from redis.backoff import ExponentialBackoff
r = redis.asyncio.Redis(host=h, retry=Retry(ExponentialBackoff(), 3), retry_on_error=[ConnectionError], socket_keepalive=True)
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

from redis.exceptions import ConnectionError

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

Try / catch

from redis.retry import Retry
from redis.backoff import ExponentialBackoff
from redis.exceptions import ConnectionError

r = redis.asyncio.Redis(
    host=h,
    retry=Retry(ExponentialBackoff(), 3),
    retry_on_error=[ConnectionError],
    socket_keepalive=True,
)

Prevention

When it happens

Trigger: Reading any response when the peer has reset/closed the socket mid-reply; partial RESP frame then RST; TLS truncation; reader feed_eof with exception. The first read after a dead-pool-reuse surfaces here.

Common situations: Server failover; LB idle eviction between request and response; client-output-buffer-limit disconnecting during a big bulk reply; forked process sharing the reader; abrupt server kill -9.

Related errors


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

Appendix: source

Thrown at redis/asyncio/connection.py:1314

                            push_request=push_request,
                        )
            else:
                response = await self._read_response_from_parser(
                    disable_decoding=disable_decoding,
                    push_request=push_request,
                )
        except asyncio.TimeoutError:
            if timeout is not None:
                # user requested timeout, return None. Operation can be retried
                return None
            # it was a self.socket_timeout error.
            if disconnect_on_error:
                await self.disconnect(nowait=True)
            raise TimeoutError(f"Timeout reading from {host_error}")
        except OSError as e:
            if disconnect_on_error:
                await self.disconnect(nowait=True)
            raise ConnectionError(f"Error while reading from {host_error} : {e.args}")
        except BaseException:
            # Also by default close in case of BaseException.  A lot of code
            # relies on this behaviour when doing Command/Response pairs.
            # See #1128.
            if disconnect_on_error:
                await self.disconnect(nowait=True)
            raise

        if self.health_check_interval:
            next_time = asyncio.get_running_loop().time() + self.health_check_interval
            self.next_health_check = next_time

        if isinstance(response, ResponseError):
            raise response from None
        return response

    async def _read_response_from_parser(
        self, disable_decoding: bool = False, push_request: bool | None = False

View on GitHub (pinned to 6a6b581b48)