redis/redis-py · warning · LockError
Unable to acquire lock within the time specified
Error message
Unable to acquire lock within the time specified
What it means
Raised as redis.exceptions.LockError by Lock.__enter__ (redis/lock.py:170). When using the lock as a context manager, __enter__ calls acquire(); if acquire() returns False (it could not obtain the lock within blocking_timeout, or blocking was False and the lock was held), __enter__ raises so the `with` block never executes. LockError subclasses ValueError.
Source
Thrown at redis/lock.py:170
self.raise_on_release_error = raise_on_release_error
self.local = threading.local() if self.thread_local else SimpleNamespace()
self.local.token = None
self.register_scripts()
def register_scripts(self) -> None:
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)
def __enter__(self) -> "Lock":
if self.acquire():
return self
raise LockError(
"Unable to acquire lock within the time specified",
lock_name=self.name,
)
def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType],
) -> None:
try:
self.release()
except LockError:
if self.raise_on_release_error:
raise
logger.warning(
"Lock was unlocked or no longer owned when exiting context manager."
)View on GitHub (pinned to da03cdc7e8)
Solutions
- Catch redis.exceptions.LockError around the `with` statement and degrade gracefully (skip, queue, or retry).
- Increase blocking_timeout (or set a lock timeout so stale locks expire sooner).
- Ensure lock holders always release in a finally block, and set a sensible lock timeout so crashed holders' locks expire.
- Use a unique lock name per resource to avoid false contention.
- If non-blocking semantics are wanted, handle the False return / LockError as 'busy, try later'.
Example fix
// before
with client.lock('job-1', blocking_timeout=5):
do_work() # LockError if not acquired in 5s
// after
from redis.exceptions import LockError
try:
with client.lock('job-1', blocking_timeout=30):
do_work()
except LockError:
log.info('job-1 busy, skipping this run') Defensive patterns
Strategy: try-catch
Validate before calling
from redis.exceptions import LockError
# probe non-blocking first to avoid the LockError from __enter__
lock = client.lock('job-1')
if not lock.acquire(blocking=False):
log.info('job-1 busy')
else:
try:
do_work()
finally:
lock.release() Try / catch
from redis.exceptions import LockError
try:
with client.lock('job-1', blocking_timeout=30):
do_work()
except LockError:
log.info('job-1 busy, skipping') Prevention
- Catch LockError around the `with client.lock(...)` and degrade gracefully.
- Set a lock timeout so crashed holders' locks expire; size blocking_timeout to the workload.
- Use a unique lock name per resource to avoid false contention.
- Always release in a finally block (or use the context manager) so locks don't leak.
- For non-blocking semantics, acquire(blocking=False) and handle the False return explicitly.
When it happens
Trigger: Using `with client.lock(name, blocking_timeout=N):` (or blocking=False) when the lock key is already held by another holder for longer than blocking_timeout, or when blocking=False and the lock is contended.
Common situations: A previous holder crashed without releasing (TTL still running); high contention on a hot lock name; blocking_timeout too short for the workload; deadlock between competing workers.
Related errors
- Cannot release a lock that's not owned or is already unlocke
- Unable to acquire lock within the time specified
- Cannot reacquire a lock that's no longer owned
- Watched variable changed.
- Cannot release a lock that's not owned or is already unlocke
AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04).
Data as JSON: /data/errors/e6f57114fc37494d.json.
Report an issue: GitHub.