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 by SentinelManagedConnection.read_response (redis/sentinel.py:91). When a Sentinel-managed connection used for the master role receives a ReadOnlyError from Redis, it means a failover occurred and the instance the client treated as master has been demoted to a replica (replicas reject writes with READONLY). The library calls self.disconnect() and raises redis.exceptions.ConnectionError so the next operation forces Sentinel to re-discover the new master.

Source

Thrown at redis/sentinel.py:91

        disconnect_on_error: Optional[bool] = False,
        push_request: Optional[bool] = False,
    ):
        try:
            return 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.
                self.disconnect()
                raise ConnectionError("The previous master is now a slave")
            raise


class SentinelManagedSSLConnection(SentinelManagedConnection, SSLConnection):
    pass


class SentinelConnectionPoolProxy:
    def __init__(
        self,
        connection_pool,
        is_master,
        check_connection,
        service_name,
        sentinel_manager,
    ):
        self.connection_pool_ref = weakref.ref(connection_pool)
        self.is_master = is_master

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Retry the operation: the next attempt triggers get_master_address() which re-queries Sentinel and connects to the new master.
  2. Wrap write operations in a retry/backoff loop catching redis.exceptions.ConnectionError.
  3. Ensure Sentinel quorum and sentinel_discover_* latency are healthy so re-discovery is fast.
  4. Tune connection_pool kwargs (e.g. lower health_check_interval, max_connections) so stale connections are reaped sooner.

Example fix

# before
client = sentinel.master_for('mymaster', socket_timeout=0.5)
client.set('k', 'v')  # may raise mid-failover
# after
from redis.exceptions import ConnectionError
for attempt in range(5):
    try:
        client.set('k', 'v')
        break
    except ConnectionError:
        time.sleep(0.1 * (2 ** attempt))
Defensive patterns

Strategy: retry

Try / catch

import time
from redis.exceptions import ConnectionError as RedisConnectionError

def write_with_failover_retry(client, *args, max_attempts=5, **kwargs):
    last_err = None
    for attempt in range(max_attempts):
        try:
            return client.set(*args, **kwargs)
        except RedisConnectionError as e:
            if 'previous master is now a slave' not in str(e).lower():
                raise
            last_err = e
            time.sleep(0.1 * (2 ** attempt))
    raise last_err

Prevention

When it happens

Trigger: A Sentinel-managed master connection (obtained via Sentinel.master_for(...)) performs a write/read-write command after a Sentinel failover has demoted the old master. The demoted node returns ReadOnlyError, which is caught in read_response; because connection_pool.is_master is True, the connection is torn down and this ConnectionError is raised.

Common situations: During or immediately after a Redis Sentinel failover; client holds stale pooled connections to the old master; failover completed but client's master_address cache has not yet been refreshed; network blip causing transient failover.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/195a00d68a091eac.json. Report an issue: GitHub.