{"record":{"id":"c5d47d88e0776d55","repo":"redis/redis-py","slug":"cannot-reacquire-a-lock-that-s-no-longer-owned","errorCode":null,"errorMessage":"Cannot reacquire a lock that's no longer owned","messagePattern":"Cannot reacquire a lock that's no longer owned","errorType":"exception","errorClass":"LockNotOwnedError","httpStatus":null,"severity":"error","filePath":"redis/asyncio/lock.py","lineNumber":344,"sourceCode":"\n    def reacquire(self) -> Awaitable[Literal[True]]:\n        \"\"\"\n        Resets a TTL of an already acquired lock back to a timeout value.\n        \"\"\"\n        if self.local.token is None:\n            raise LockError(\"Cannot reacquire an unlocked lock\")\n        if self.timeout is None:\n            raise LockError(\"Cannot reacquire a lock with no timeout\")\n        return self.do_reacquire()\n\n    async def do_reacquire(self) -> Literal[True]:\n        timeout = int(self.timeout * 1000)\n        if not bool(\n            await self.lua_reacquire(\n                keys=[self.name], args=[self.local.token, timeout], client=self.redis\n            )\n        ):\n            raise LockNotOwnedError(\"Cannot reacquire a lock that's no longer owned\")\n        return True\n","sourceCodeStart":326,"sourceCodeEnd":346,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/asyncio/lock.py#L326-L346","documentation":"do_reacquire runs the Lua reacquire script; if the key is gone/TTL-expired or the token differs, it returns 0 and LockNotOwnedError is raised. The lock expired before the reacquire request reached the server, so the TTL could not be reset.","triggerScenarios":"Calling reacquire() after the lock TTL already expired; another holder took over the key between the last operation and reacquire.","commonSituations":"Renewal scheduled too late; long event-loop/GC pause pushing reacquire past expiry.","solutions":["Reacquire before expiry with margin.","Catch LockNotOwnedError and re-acquire the lock fresh.","Use a longer base timeout to give renewal more room."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from redis.exceptions import LockNotOwnedError\ntry:\n    await lock.reacquire()\nexcept LockNotOwnedError:\n    # lock expired before reacquire: re-acquire fresh\n    await lock.acquire()","preventionTips":["Reacquire before expiry with margin.","Catch LockNotOwnedError and re-acquire rather than assuming success.","Use a longer base timeout when renewal timing is uncertain."],"tags":["lock","ttl","distributed-lock","ownership","async"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}