redis/redis-py · error · ConnectionError

Connection not ready

Error message

Connection not ready

What it means

Raised as ConnectionError('Connection not ready') by ConnectionPool.get_connection / the blocking pool after a connection that still had unread socket data was disconnected and reconnected and still reports can_read() True (and client-side caching and maintenance notifications are not active, which would legitimately leave push data on the socket). It indicates the reconnected socket is not in a clean command-ready state, so handing it out would corrupt the request/response framing.

Solutions

  1. Ensure every command's response is fully read before returning the connection to the pool (avoid partial reads in pipelines/transactions).
  2. Treat this as transient and retry the operation with backoff; the pool releases the bad connection on raise.
  3. If it recurs, enable client-side caching or maintenance notifications only where appropriate, or review for server push traffic the client isn't expecting.

Example fix

# before - response not fully consumed, conn returned dirty
pipe = r.pipeline()
pipe.set('a', 1)
pipe.execute()  # partially read elsewhere -> next get_connection can raise
# after - always drain the response, and retry on transient ConnectionError
for attempt in range(3):
    try:
        return r.get('a')
    except redis.exceptions.ConnectionError:
        continue
Defensive patterns

Strategy: retry

Validate before calling

# No deterministic pre-check exists; ensure connections are clean before release by
# fully reading every response:
assert not conn.can_read(), 'returning a connection with unread data'
# (Call this in debug builds / pool release hooks.)

Try / catch

import time
from redis.exceptions import ConnectionError

for attempt in range(4):
    try:
        return r.get('key')
    except ConnectionError as e:
        if 'Connection not ready' in str(e) and attempt < 3:
            time.sleep(0.1 * (2 ** attempt))
            continue
        raise

Prevention

When it happens

Trigger: A pooled connection was returned with unread bytes (e.g. a previous command's reply not fully consumed, or an unsolicited server push), the pool disconnects/reconnects, and the fresh socket still shows pending data — typically due to a server-side push, a half-read pipeline reply, or a flaky network path.

Common situations: Not fully consuming responses (abandoned read_response). Server pushing data right after connect. Aggressive health-check or pubsub traffic on a non-cache, non-maintenance pool. Transient socket corruption.

Related errors


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

Appendix: source

Thrown at redis/connection.py:3309

            # a command. if not, the connection was either returned to the
            # pool before all data has been read or the socket has been
            # closed. either way, reconnect and verify everything is good.
            try:
                if (
                    connection.can_read()
                    and self.cache is None
                    and not self.maint_notifications_enabled()
                ):
                    raise ConnectionError("Connection has data")
            except (ConnectionError, TimeoutError, OSError):
                connection.disconnect()
                connection.connect()
                if (
                    connection.can_read()
                    and self.cache is None
                    and not self.maint_notifications_enabled()
                ):
                    raise ConnectionError("Connection not ready")
        except BaseException:
            # release the connection back to the pool so that we don't
            # leak it
            self.release(connection)
            raise

        if is_created:
            record_connection_create_time(
                connection_pool=self,
                duration_seconds=time.monotonic() - start_time_created,
            )

        return connection

    def get_encoder(self) -> Encoder:
        "Return an encoder based on encoding settings"
        kwargs = self.connection_kwargs
        return Encoder(

View on GitHub (pinned to 6a6b581b48)