{"record":{"id":"ebde22b441ce352a","repo":"redis/redis-py","slug":"the-previous-master-is-now-a-slave","errorCode":null,"errorMessage":"The previous master is now a slave","messagePattern":"The previous master is now a slave","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"warning","filePath":"redis/asyncio/sentinel.py","lineNumber":94,"sourceCode":"        disconnect_on_error: Optional[float] = True,\n        push_request: Optional[bool] = False,\n    ):\n        try:\n            return await super().read_response(\n                disable_decoding=disable_decoding,\n                timeout=timeout,\n                disconnect_on_error=disconnect_on_error,\n                push_request=push_request,\n            )\n        except ReadOnlyError:\n            if self.connection_pool.is_master:\n                # When talking to a master, a ReadOnlyError when likely\n                # indicates that the previous master that we're still connected\n                # to has been demoted to a slave and there's a new master.\n                # calling disconnect will force the connection to re-query\n                # sentinel during the next connect() attempt.\n                await self.disconnect()\n                raise ConnectionError(\"The previous master is now a slave\")\n            raise\n\n\nclass SentinelManagedSSLConnection(SentinelManagedConnection, SSLConnection):\n    pass\n\n\nclass SentinelConnectionPool(ConnectionPool):\n    \"\"\"\n    Sentinel backed connection pool.\n\n    If ``check_connection`` flag is set to True, SentinelManagedConnection\n    sends a PING command right after establishing the connection.\n    \"\"\"\n\n    def __init__(self, service_name, sentinel_manager, **kwargs):\n        kwargs[\"connection_class\"] = kwargs.get(\n            \"connection_class\",","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/sentinel.py#L76-L112","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the command — the disconnect forces re-discovery of the new master on the next attempt.","Wrap writes in a retry loop that catches ConnectionError and re-issues the command on a fresh client/connection.","Tune Sentinel/health-check intervals so failover detection happens faster and connections refresh sooner."],"exampleFix":"# before\nawait master_client.set(\"k\", \"v\")  # may raise after failover\n# after\nfor attempt in range(3):\n    try:\n        await master_client.set(\"k\", \"v\")\n        break\n    except ConnectionError:\n        await asyncio.sleep(0.5)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from redis.exceptions import ConnectionError\nfor attempt in range(retries):\n    try:\n        return await master_client.execute_command(*args)\n    except ConnectionError as e:\n        if \"previous master is now a slave\" in str(e):\n            await asyncio.sleep(backoff)\n            continue\n        raise","preventionTips":["Always retry writes on sentinel master clients to absorb failover transients.","Keep socket_timeout short so stale connections fail fast and re-discover."],"tags":["sentinel","failover","connection","async"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}