redis/redis-py · error · ConnectionError
READONLY command failed
Error message
READONLY command failed
What it means
Raised by RedisCluster.on_connect (redis/asyncio/cluster.py:786) when the READONLY command reply is not 'OK'. When read_from_replicas or load_balancing_strategy is set, each new connection sends READONLY so replica connections accept reads. If the server refuses (returns non-OK), the connection setup fails with ConnectionError, which the pool treats as a connection failure.
Source
Thrown at redis/asyncio/cluster.py:786
if hasattr(self, "_initialize") and not self._initialize:
_warn(f"{self._DEL_MESSAGE} {self!r}", ResourceWarning, source=self)
try:
context = {"client": self, "message": self._DEL_MESSAGE}
_grl().call_exception_handler(context)
except RuntimeError:
pass
async def on_connect(self, connection: Connection) -> None:
await connection.on_connect()
# Sending READONLY command to server to configure connection as
# readonly. Since each cluster node may change its server type due
# to a failover, we should establish a READONLY connection
# regardless of the server type. If this is a primary connection,
# READONLY would not affect executing write commands.
await connection.send_command("READONLY")
if str_if_bytes(await connection.read_response()) != "OK":
raise ConnectionError("READONLY command failed")
def get_nodes(self) -> List["ClusterNode"]:
"""Get all nodes of the cluster."""
return list(self.nodes_manager.nodes_cache.values())
def get_primaries(self) -> List["ClusterNode"]:
"""Get the primary nodes of the cluster."""
return self.nodes_manager.get_nodes_by_server_type(PRIMARY)
def get_replicas(self) -> List["ClusterNode"]:
"""Get the replica nodes of the cluster."""
return self.nodes_manager.get_nodes_by_server_type(REPLICA)
def get_random_node(self) -> "ClusterNode":
"""Get a random node of the cluster."""
return random.choice(list(self.nodes_manager.nodes_cache.values()))
def get_default_node(self) -> "ClusterNode":View on GitHub (pinned to da03cdc7e8)
Solutions
- Ensure the target is a real Redis Cluster node (run CLUSTER INFO).
- If you do not need replica reads, drop read_from_replicas/load_balancing_strategy so on_connect skips READONLY.
- Verify the ACL user can issue READONLY and that replicas are reachable.
- Retry: this raises ConnectionError so the retry layer will attempt reconnects if configured.
Example fix
// before c = RedisCluster(host='localhost', port=16379, read_from_replicas=True) // (against a standalone Redis) // after c = redis.asyncio.Redis(host='localhost', port=6379) # standalone, no READONLY # or, for a real cluster, keep read_from_replicas=True and verify replicas exist
Defensive patterns
Strategy: try-catch
Try / catch
from redis.exceptions import ConnectionError
try:
await c.get('k')
except ConnectionError as e:
if 'READONLY' in str(e):
log.error('target may not be a cluster node or ACL denies READONLY')
raise Prevention
- Confirm the target is a Redis Cluster node (CLUSTER INFO).
- Drop read_from_replicas unless you actually have replicas and need them.
- Ensure the ACL user can issue READONLY.
When it happens
Trigger: Connecting read_from_replicas=True to an endpoint that rejects READONLY: a standalone (non-cluster) Redis, a node where the connection landed on a primary that disallows READONLY under certain configs, or an ACL/permission denial. on_connect runs after the standard handshake.
Common situations: Pointing a cluster client at a non-cluster Redis; ACL user lacking permission; proxy that does not implement READONLY; connecting before the node has joined the cluster.
Related errors
- A {type(error).__name__} occurred while watching one or more
- Argument 'db' must be 0 or None in cluster mode
- Unix domain socket is not supported in cluster mode
- RedisCluster requires at least one node to discover the clus
- Maintenance notifications are only supported with RESP versi
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/ecc974bc2b28ca40.json.
Report an issue: GitHub.