{"record":{"id":"313e23c2a41db5bc","repo":"redis/redis-py","slug":"readonly-command-failed-313e23","errorCode":null,"errorMessage":"READONLY command failed","messagePattern":"READONLY command failed","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"redis/cluster.py","lineNumber":1026,"sourceCode":"                    # Client was already disconnected. do nothing\n                    pass\n\n    def on_connect(self, connection):\n        \"\"\"\n        Initialize the connection, authenticate and select a database and send\n         READONLY if it is set during object initialization.\n        \"\"\"\n        connection.on_connect()\n\n        if self.read_from_replicas or self.load_balancing_strategy:\n            # Sending READONLY command to server to configure connection as\n            # readonly. Since each cluster node may change its server type due\n            # to a failover, we should establish a READONLY connection\n            # regardless of the server type. If this is a primary connection,\n            # READONLY would not affect executing write commands.\n            connection.send_command(\"READONLY\")\n            if str_if_bytes(connection.read_response()) != \"OK\":\n                raise ConnectionError(\"READONLY command failed\")\n\n        if self.user_on_connect_func is not None:\n            self.user_on_connect_func(connection)\n\n    def get_redis_connection(self, node: \"ClusterNode\") -> Redis:\n        if not node.redis_connection:\n            with self._lock:\n                if not node.redis_connection:\n                    self.nodes_manager.create_redis_connections([node])\n        return node.redis_connection\n\n    def get_node(self, host=None, port=None, node_name=None):\n        return self.nodes_manager.get_node(host, port, node_name)\n\n    def get_primaries(self):\n        return self.nodes_manager.get_nodes_by_server_type(PRIMARY)\n\n    def get_replicas(self):","sourceCodeStart":1008,"sourceCodeEnd":1044,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/cluster.py#L1008-L1044","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclient = RedisCluster(host='localhost', port=7000, read_from_replicas=True)\n\n// after (replica reads not needed)\nclient = RedisCluster(host='localhost', port=7000)","handlingStrategy":"validation","validationCode":"# Validate cluster mode and READONLY support before constructing with read_from_replicas\nimport redis\ninfo = redis.Redis(host, port).cluster('INFO')  # raises if not cluster\nif 'cluster_enabled:1' not in info:\n    raise RuntimeError('Not a cluster node; cannot use read_from_replicas')","typeGuard":"def supports_readonly(conn: redis.Redis) -> bool:\n    try:\n        return conn.execute_command('COMMAND', 'INFO', 'READONLY') is not None\n    except redis.ResponseError:\n        return False","tryCatchPattern":"try:\n    client = RedisCluster(host, port, read_from_replicas=True)\nexcept ConnectionError as e:\n    if 'READONLY command failed' in str(e):\n        # fall back without replica reads\n        client = RedisCluster(host, port)","preventionTips":["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."],"tags":["connection","replica-read","cluster","configuration"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}