redis/redis-py · error · ConnectionError
READONLY command failed
Error message
READONLY command failed
What it means
Raised as a ConnectionError during the cluster connection pool's on_connect hook when the READONLY command (sent to enable replica reads) does not return the expected 'OK' response. The client sends READONLY on every new connection when read_from_replicas or load_balancing_strategy is configured, so a non-OK reply means the server rejected or could not process the command. This prevents the client from silently using connections that cannot serve replica reads.
Solutions
- Verify the target is actually a Redis Cluster deployment (not a standalone Redis) by running CLUSTER INFO on the node.
- If you do not need replica reads, remove read_from_replicas=True and load_balancing_strategy from your RedisCluster constructor so the client stops sending READONLY.
- Check Redis server ACL/permissions to ensure the authenticated user is allowed to run the READONLY command (check aclfile or ACL LIST).
- Upgrade the Redis server to a version that supports cluster READONLY semantics if you are on an old release.
Example fix
// before client = RedisCluster(host='localhost', port=7000, read_from_replicas=True) // after (replica reads not needed) client = RedisCluster(host='localhost', port=7000)
Defensive patterns
Strategy: validation
Validate before calling
# Validate cluster mode and READONLY support before constructing with read_from_replicas
import redis
info = redis.Redis(host, port).cluster('INFO') # raises if not cluster
if 'cluster_enabled:1' not in info:
raise RuntimeError('Not a cluster node; cannot use read_from_replicas') Type guard
def supports_readonly(conn: redis.Redis) -> bool:
try:
return conn.execute_command('COMMAND', 'INFO', 'READONLY') is not None
except redis.ResponseError:
return False Try / catch
try:
client = RedisCluster(host, port, read_from_replicas=True)
except ConnectionError as e:
if 'READONLY command failed' in str(e):
# fall back without replica reads
client = RedisCluster(host, port) Prevention
- Only set read_from_replicas or load_balancing_strategy when connecting to a confirmed Redis Cluster deployment.
- Verify cluster mode with CLUSTER INFO before constructing the client.
- Ensure the authenticated ACL user has permission for the READONLY command.
When it happens
Trigger: Constructing RedisCluster with read_from_replicas=True or a load_balancing_strategy, then issuing any command that opens a connection to a node whose server does not return 'OK' to the READONLY command. This is triggered inside PerthConnectionPool.on_connect (cluster.py:1011-1026) on every new connection.
Common situations: Connecting a RedisCluster client to a standalone (non-cluster) Redis instance, pointing at a Redis version that does not support READONLY in the expected form, hitting an authentication/AACL issue where the READONLY command is denied, or a transient server error during failover that causes the server to reject READONLY.
Related errors
- Argument 'db' must be 0 or None in cluster mode
- Cannot enable maintenance notifications for connection…
- Cluster mode is not enabled on this node
- Cluster Node has no redis_connection
- Error setting client name
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/313e23c2a41db5bc.
Report an issue: GitHub.
Appendix: source
Thrown at redis/cluster.py:1026
# Client was already disconnected. do nothing
pass
def on_connect(self, connection):
"""
Initialize the connection, authenticate and select a database and send
READONLY if it is set during object initialization.
"""
connection.on_connect()
if self.read_from_replicas or self.load_balancing_strategy:
# 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.
connection.send_command("READONLY")
if str_if_bytes(connection.read_response()) != "OK":
raise ConnectionError("READONLY command failed")
if self.user_on_connect_func is not None:
self.user_on_connect_func(connection)
def get_redis_connection(self, node: "ClusterNode") -> Redis:
if not node.redis_connection:
with self._lock:
if not node.redis_connection:
self.nodes_manager.create_redis_connections([node])
return node.redis_connection
def get_node(self, host=None, port=None, node_name=None):
return self.nodes_manager.get_node(host, port, node_name)
def get_primaries(self):
return self.nodes_manager.get_nodes_by_server_type(PRIMARY)
def get_replicas(self):View on GitHub (pinned to 6a6b581b48)