redis/redis-py · error · LockError
Cannot reacquire an unlocked lock
Error message
Cannot reacquire an unlocked lock
What it means
reacquire() resets the lock's TTL back to the original timeout; if the local token is None the lock is not held on this instance, so it raises LockError before contacting Redis. The same client-side guard as release/extend.
Solutions
- Guard with 'if await lock.owned()' before reacquire.
- Use thread_local=False for cross-task renewal.
- Do not reacquire after release.
Example fix
# before
await lock.reacquire() # before any acquire -> LockError
# after
if await lock.owned():
await lock.reacquire() Defensive patterns
Strategy: validation
Validate before calling
if await lock.owned():
await lock.reacquire() Prevention
- Guard reacquire with 'await lock.owned()'.
- Use thread_local=False for cross-task renewal.
When it happens
Trigger: Calling reacquire() before acquire(), after release(), or from a different thread/task than the acquirer with thread_local=True.
Common situations: Renewal logic run before/after ownership; cross-task token invisibility.
Related errors
- Cannot extend a lock that's no longer owned
- Cannot extend an unlocked lock
- Cannot reacquire a lock that's no longer owned
- Cannot release a lock that's no longer owned
- Cannot release a lock that's not owned or is already…
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/4be726eefc62b94b.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/lock.py:332
async def do_extend(self, additional_time, replace_ttl) -> Literal[True]:
additional_time = int(additional_time * 1000)
if not bool(
await self.lua_extend(
keys=[self.name],
args=[self.local.token, additional_time, replace_ttl and "1" or "0"],
client=self.redis,
)
):
raise LockNotOwnedError("Cannot extend a lock that's no longer owned")
return True
def reacquire(self) -> Awaitable[Literal[True]]:
"""
Resets a TTL of an already acquired lock back to a timeout value.
"""
if self.local.token is None:
raise LockError("Cannot reacquire an unlocked lock")
if self.timeout is None:
raise LockError("Cannot reacquire a lock with no timeout")
return self.do_reacquire()
async def do_reacquire(self) -> Literal[True]:
timeout = int(self.timeout * 1000)
if not bool(
await self.lua_reacquire(
keys=[self.name], args=[self.local.token, timeout], client=self.redis
)
):
raise LockNotOwnedError("Cannot reacquire a lock that's no longer owned")
return True
View on GitHub (pinned to 6a6b581b48)