redis/redis-py · error · RedisError
MONITOR failed
Error message
MONITOR failed: {response} What it means
Raised inside Monitor.__aenter__ after sending MONITOR and reading the server reply: if the reply does not pass the bool_ok check (i.e. it is not the simple-string "OK"), the library treats MONITOR setup as failed and aborts. The f-string interpolates the raw response so the actual server reply is visible. This is a hard failure that prevents the monitor context from being entered.
Solutions
- Grant the connecting user permission to run MONITOR (ACL: +@admin or +monitor).
- Check the interpolated response string — if it is an ACL error, fix credentials; if it is MOVED/CLUSTERDOWN, you are hitting a cluster where MONITOR must target a specific node.
- Avoid MONITOR in production; use it only for local debugging.
Example fix
// before
async with client.monitor() as m:
...
// after
# ensure the ACL user can run MONITOR
# redis-cli ACL SETUSER monitor_user on >pass +monitor on ~*
async with client.monitor() as m:
... Defensive patterns
Strategy: try-catch
Validate before calling
# Before opening a monitor, verify the user can run MONITOR: info = await client.acl_whoami() # or check ACL GETUSER # There is no pure-client precondition for MONITOR success; rely on ACL setup.
Try / catch
try:
async with client.monitor() as m:
...
except RedisError as e:
if 'MONITOR failed' in str(e):
# log and degrade; MONITOR unavailable for this user/env
... Prevention
- Grant the connecting ACL user +monitor (or +@admin).
- Use MONITOR only for local debugging, never in the hot path.
When it happens
Trigger: Calling async with redis.asyncio.Redis(...).monitor() as m: when the server returns a non-OK reply to MONITOR — e.g. the connected user lacks the admin permission required to run MONITOR, the server returned an -ERR / -BUSY /moved, or a RESP3 push/redirect was misread as the MONITOR acknowledgment.
Common situations: Using a least-privilege ACL user that lacks the +@admin or MONITOR permission; running MONITOR against Redis Cloud / a managed instance where it is disabled; a failover happening exactly as MONITOR is issued so the reply is an error.
Related errors
- MONITOR failed
- A non health check response was cleaned by execute_command
- ACL LOG count must be an integer
- Bad response from PING health check
- Cannot set 'nopass' and supply 'passwords' or…
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/5ee52de565c02c5c.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/client.py:1092
monitor_re = re.compile(r"\[(\d+) (.*?)\] (.*)")
command_re = re.compile(r'"(.*?)(?<!\\)"')
def __init__(self, connection_pool: ConnectionPool):
self.connection_pool = connection_pool
self.connection: Optional[Connection] = None
async def connect(self):
if self.connection is None:
self.connection = await self.connection_pool.get_connection()
async def __aenter__(self):
await self.connect()
await self.connection.send_command("MONITOR")
# check that monitor returns 'OK', but don't return it to user
response = await self.connection.read_response()
if not bool_ok(response):
raise RedisError(f"MONITOR failed: {response}")
return self
async def __aexit__(self, *args):
await self.connection.disconnect()
await self.connection_pool.release(self.connection)
async def next_command(self) -> MonitorCommandInfo:
"""Parse the response from a monitor command"""
await self.connect()
response = await self.connection.read_response()
if isinstance(response, bytes):
response = self.connection.encoder.decode(response, force=True)
command_time, command_data = response.split(" ", 1)
m = self.monitor_re.match(command_data)
db_id, client_info, command = m.groups()
command = " ".join(self.command_re.findall(command))
# Redis escapes double quotes because each piece of the command
# string is surrounded by double quotes. We don't have thatView on GitHub (pinned to 6a6b581b48)