redis/redis-py · warning · ConnectionError

The previous master is now a slave

Error message

The previous master is now a slave

What it means

Raised as a ConnectionError inside SentinelManagedConnection.read_response when a ReadOnlyError is received on a connection the pool believes is the master. A ReadOnlyError from a node we think is master means a failover demoted it; the code disconnects so the next connect() re-queries Sentinel for the new master. This is a transient, self-healing failover signal rather than a permanent fault.

Solutions

  1. Retry the command — the disconnect forces re-discovery of the new master on the next attempt.
  2. Wrap writes in a retry loop that catches ConnectionError and re-issues the command on a fresh client/connection.
  3. Tune Sentinel/health-check intervals so failover detection happens faster and connections refresh sooner.

Example fix

# before
await master_client.set("k", "v")  # may raise after failover
# after
for attempt in range(3):
    try:
        await master_client.set("k", "v")
        break
    except ConnectionError:
        await asyncio.sleep(0.5)
Defensive patterns

Strategy: retry

Try / catch

from redis.exceptions import ConnectionError
for attempt in range(retries):
    try:
        return await master_client.execute_command(*args)
    except ConnectionError as e:
        if "previous master is now a slave" in str(e):
            await asyncio.sleep(backoff)
            continue
        raise

Prevention

When it happens

Trigger: Sending any command through a sentinel master_for() client after a Sentinel-initiated failover has demoted the node we are connected to, before the pool has rediscovered the new master. The server replies READONLY error, triggering this branch because connection_pool.is_master is True.

Common situations: Sentinel failover in progress or recently completed. Long-lived connections holding onto a stale master. Network partition that caused a demotion. Running writes during/just after a failover window.

Related errors


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

Appendix: source

Thrown at redis/asyncio/sentinel.py:94

        disconnect_on_error: Optional[float] = True,
        push_request: Optional[bool] = False,
    ):
        try:
            return await super().read_response(
                disable_decoding=disable_decoding,
                timeout=timeout,
                disconnect_on_error=disconnect_on_error,
                push_request=push_request,
            )
        except ReadOnlyError:
            if self.connection_pool.is_master:
                # When talking to a master, a ReadOnlyError when likely
                # indicates that the previous master that we're still connected
                # to has been demoted to a slave and there's a new master.
                # calling disconnect will force the connection to re-query
                # sentinel during the next connect() attempt.
                await self.disconnect()
                raise ConnectionError("The previous master is now a slave")
            raise


class SentinelManagedSSLConnection(SentinelManagedConnection, SSLConnection):
    pass


class SentinelConnectionPool(ConnectionPool):
    """
    Sentinel backed connection pool.

    If ``check_connection`` flag is set to True, SentinelManagedConnection
    sends a PING command right after establishing the connection.
    """

    def __init__(self, service_name, sentinel_manager, **kwargs):
        kwargs["connection_class"] = kwargs.get(
            "connection_class",

View on GitHub (pinned to 6a6b581b48)