python/cpython · error · RuntimeError
cannot wait on un-acquired lock
Error message
cannot wait on un-acquired lock
What it means
asyncio.Condition.wait() requires the calling task to hold the condition's lock: it releases it before sleeping and re-acquires on wake. Calling wait() without a prior acquire() would release a lock you do not own, corrupting synchronization, so it raises RuntimeError immediately.
Source
Thrown at Lib/asyncio/locks.py:261
return f'<{res[1:-1]} [{extra}]>'
async def wait(self):
"""Wait until notified.
If the calling task has not acquired the lock when this
method is called, a RuntimeError is raised.
This method releases the underlying lock, and then blocks
until it is awakened by a notify() or notify_all() call for
the same condition variable in another task. Once
awakened, it re-acquires the lock and returns True.
This method may return spuriously,
which is why the caller should always
re-check the state and be prepared to wait() again.
"""
if not self.locked():
raise RuntimeError('cannot wait on un-acquired lock')
fut = self._get_loop().create_future()
self.release()
try:
try:
self._waiters.append(fut)
try:
await fut
return True
finally:
self._waiters.remove(fut)
finally:
# Must re-acquire lock even if wait is cancelled.
# We only catch CancelledError here, since we don't want any
# other (fatal) errors with the future to cause us to spin.
err = None
while True:View on GitHub (pinned to bc6749cc3b)
Solutions
- Always wrap: async with cond: await cond.wait()
- Re-acquire before notify paths too: async with cond: cond.notify_all()
- If using a separate lock, construct Condition(lock=that_lock) and hold it before waiting
Example fix
# before
await cond.wait() # RuntimeError: un-acquired lock
# after
async with cond:
await cond.wait() Defensive patterns
Strategy: validation
Validate before calling
if not cond.locked():
# wait() would raise; acquire the lock first (async with cond) Prevention
- Always 'async with cond:' around wait()
- The same task must hold the lock while waiting
- Give a shared lock to Condition(lock=...) if ownership spans helpers
When it happens
Trigger: await cond.wait() without 'async with cond'; calling wait() after the with-block exited; a helper task waiting on a condition whose lock is held by a different task.
Common situations: Translating threading.Condition patterns where the lock is implicit; forgetting that asyncio.Condition bundles its own lock; calling wait() in except/finally after the context exited early.
Related errors
- cannot notify on un-acquired lock
- Lock is not acquired.
- BoundedSemaphore released too many times
- {self!r} is bound to a different event loop
- Failed to fetch glossary.json
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/382d89a380ef7d0c.
Report an issue: GitHub.