redis/redis-py · error · LockError
Unable to acquire lock within the time specified
Error message
Unable to acquire lock within the time specified
What it means
When a Lock is used as an async context manager, __aenter__ calls acquire(); if it returns False (the blocking_timeout elapsed without winning the lock), LockError is raised so the 'async with' body never executes. A direct (non-context-manager) acquire() instead returns False, so this error specifically signals context-manager acquisition timeout.
Solutions
- Increase blocking_timeout when constructing the Lock.
- Ensure locks are released promptly and the token/thread_local setup is correct.
- Catch LockError and degrade gracefully instead of failing the request.
- Shorten the critical section protected by the lock.
Example fix
# before
lock = Lock(r, 'resource', blocking_timeout=1)
async with lock: # raises LockError under contention
...
# after
from redis.exceptions import LockError
lock = Lock(r, 'resource', blocking_timeout=30)
try:
async with lock:
...
except LockError:
... # handle contention gracefully Defensive patterns
Strategy: try-catch
Try / catch
from redis.exceptions import LockError
try:
async with lock:
...
except LockError:
# contention timeout: degrade gracefully
... Prevention
- Set blocking_timeout generously relative to expected contention.
- Release locks quickly and keep critical sections short.
- Catch LockError to fall back instead of failing the caller.
When it happens
Trigger: 'async with lock:' where contention lasts longer than the lock's blocking_timeout (or default), so acquire() exhausts its retries and returns False inside __aenter__.
Common situations: High lock contention; forgotten or delayed release; critical sections longer than expected; blocking_timeout set too low; deadlock.
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 reacquire an unlocked lock
- Cannot release a lock that's no longer owned
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/79b00ee8bf2de581.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/lock.py:173
self.local = threading.local() if self.thread_local else SimpleNamespace()
self.raise_on_release_error = raise_on_release_error
self.local.token = None
self.register_scripts()
def register_scripts(self):
cls = self.__class__
client = self.redis
if cls.lua_release is None:
cls.lua_release = client.register_script(cls.LUA_RELEASE_SCRIPT)
if cls.lua_extend is None:
cls.lua_extend = client.register_script(cls.LUA_EXTEND_SCRIPT)
if cls.lua_reacquire is None:
cls.lua_reacquire = client.register_script(cls.LUA_REACQUIRE_SCRIPT)
async def __aenter__(self):
if await self.acquire():
return self
raise LockError("Unable to acquire lock within the time specified")
async def __aexit__(self, exc_type, exc_value, traceback):
try:
await self.release()
except LockError:
if self.raise_on_release_error:
raise
logger.warning(
"Lock was unlocked or no longer owned when exiting context manager."
)
async def acquire(
self,
blocking: Optional[bool] = None,
blocking_timeout: Optional[Number] = None,
token: Optional[Union[str, bytes]] = None,
):
"""View on GitHub (pinned to 6a6b581b48)