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

  1. Always wrap: async with cond: await cond.wait()
  2. Re-acquire before notify paths too: async with cond: cond.notify_all()
  3. 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

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


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/382d89a380ef7d0c. Report an issue: GitHub.