{"record":{"id":"b088730f62001e01","repo":"redis/redis-py","slug":"shutdown-seems-to-have-failed","errorCode":null,"errorMessage":"SHUTDOWN seems to have failed.","messagePattern":"SHUTDOWN seems to have failed\\.","errorType":"exception","errorClass":"RedisError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":2129,"sourceCode":"        if save and nosave:\n            raise DataError(\"SHUTDOWN save and nosave cannot both be set\")\n        args = [\"SHUTDOWN\"]\n        if save:\n            args.append(\"SAVE\")\n        if nosave:\n            args.append(\"NOSAVE\")\n        if now:\n            args.append(\"NOW\")\n        if force:\n            args.append(\"FORCE\")\n        if abort:\n            args.append(\"ABORT\")\n        try:\n            self.execute_command(*args, **kwargs)\n        except ConnectionError:\n            # a ConnectionError here is expected\n            return\n        raise RedisError(\"SHUTDOWN seems to have failed.\")\n\n    @overload\n    def slaveof(\n        self: SyncClientProtocol,\n        host: str | None = None,\n        port: int | None = None,\n        **kwargs,\n    ) -> bool: ...\n\n    @overload\n    def slaveof(\n        self: AsyncClientProtocol,\n        host: str | None = None,\n        port: int | None = None,\n        **kwargs,\n    ) -> Awaitable[bool]: ...\n\n    def slaveof(","sourceCodeStart":2111,"sourceCodeEnd":2147,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L2111-L2147","documentation":"Raised by shutdown() (redis/commands/core.py:2129) after the SHUTDOWN command returns WITHOUT raising a ConnectionError. The expected success path is that the server closes the connection during shutdown, surfacing as a ConnectionError that the method swallows and returns normally; if execute_command returns at all, the library assumes the server is still alive and raises a redis.exceptions.RedisError. This typically happens with SHUTDOWN ABORT (which cancels an in-progress shutdown and returns OK), with certain NOW/FORCE combinations, or when a replica/ACL guard prevents the shutdown.","triggerScenarios":"Calling r.shutdown(abort=True) (server returns OK instead of closing the link); calling shutdown against a node protected by min-replicas/ACL that rejects the operation; or a Redis version whose shutdown path returns a reply rather than dropping the connection.","commonSituations":"Using abort=True to cancel a shutdown in failover tests; running shutdown against a managed/Redis Cloud endpoint that intercepts it; the connection being proxied so the close is masked.","solutions":["If you intended to abort, wrap the call: try: r.shutdown(abort=True) except RedisError: pass","Verify the user has the admin/shutdown ACL permission before calling","For a real shutdown, ensure no abort flag and that the target is a writable master; expect ConnectionError as the normal outcome","Check server logs / replica lag if shutdown is being blocked by min-replicas configuration"],"exampleFix":"# before\nr.shutdown(abort=True)  # raises RedisError because server replied OK\n# after\nfrom redis.exceptions import RedisError\ntry:\n    r.shutdown(abort=True)\nexcept RedisError:\n    pass  # abort returns a reply rather than closing the connection","handlingStrategy":"try-catch","validationCode":"# Pre-check ACL for shutdown permission when feasible\nme = r.execute_command(\"ACL\", \"WHOAMI\")\n# also detect abort mode, which legitimately returns a reply\nif abort:\n    # SHUTDOWN ABORT returns OK instead of closing the connection\n    expected_reply = True","typeGuard":null,"tryCatchPattern":"from redis.exceptions import RedisError, ConnectionError\ntry:\n    r.shutdown(save=save, nosave=nosave, abort=abort)\nexcept ConnectionError:\n    pass  # normal: server closed the connection during shutdown\nexcept RedisError as e:\n    if \"SHUTDOWN seems to have failed\" in str(e):\n        # server replied instead of closing (e.g. SHUTDOWN ABORT) - inspect logs\n        pass\n    else:\n        raise","preventionTips":["Expect ConnectionError as the SUCCESS path for a real shutdown.","Wrap abort=True calls because the server returns OK rather than closing the link.","Verify the user has the +shutdown ACL flag and the node is a writable master.","Check min-replicas config if shutdown appears to be blocked."],"tags":["admin","rediserror","shutdown","runtime"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}