redis/redis-py · error · 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 (redis/asyncio/sentinel.py:94) when a ReadOnlyError is received on a connection pool flagged is_master. A ReadOnlyError from a node we believe is master means a failover has occurred: our cached master was demoted to a replica. The connection is forcibly disconnected so the next connect() re-queries Sentinel for the new master.
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 da03cdc7e8)
Solutions
- Retry the operation — the disconnect forces re-discovery of the new master on the next attempt.
- Wrap the call with a retry loop (or use the client retry_on_error with ReadOnlyError/ConnectionError) sized to the expected failover window.
- Ensure socket_timeout and retry config are tuned so rediscovery completes within your SLA.
Example fix
# before
await master.set('k', 'v') # may raise ConnectionError mid-failover
# after
for _ in range(retries):
try:
return await master.set('k', 'v')
except ConnectionError:
await asyncio.sleep(backoff) Defensive patterns
Strategy: retry
Try / catch
from redis.exceptions import ConnectionError, ReadOnlyError
for attempt in range(retries):
try:
return await master_client.execute_command(*args)
except ConnectionError:
await asyncio.sleep(backoff * (2 ** attempt)) Prevention
- Enable retry_on_error=[ConnectionError, ReadOnlyError] on the master client.
- Tune socket_timeout so rediscovery completes within your SLA.
When it happens
Trigger: Issuing a write command through a master_for(...) client during/after a Sentinel failover; the pool still holds a connection to the demoted old master which now refuses writes with READONLY error.
Common situations: Active Sentinel failover in progress or just completed; brief window between master demotion and client rediscovery; repeated writes during topology churn.
Related errors
- No slave found for {self.service_name!r}
- No master found for {service_name!r}{error_info}
- Failed to subscribe to cluster nodes: {', '.join(failed_node
- The previous master is now a slave
- No slave found for {self.service_name!r}
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/ebde22b441ce352a.json.
Report an issue: GitHub.