python/cpython · error · RuntimeError

cannot notify on un-acquired lock

Error message

cannot notify on un-acquired lock

What it means

asyncio.Condition.notify()/notify_all() raise RuntimeError when the calling task does not hold the condition's lock. The docstring in-source notes awakened tasks only resume after reacquiring the lock, so notifying without ownership would break the wakeup protocol.

Source

Thrown at Lib/asyncio/locks.py:327

        while not result:
            await self.wait()
            result = predicate()
        return result

    def notify(self, n=1):
        """By default, wake up one task waiting on this condition, if any.
        If the calling task has not acquired the lock when this method
        is called, a RuntimeError is raised.

        This method wakes up n of the tasks waiting for the condition
         variable; if fewer than n are waiting, they are all awoken.

        Note: an awakened task does not actually return from its
        wait() call until it can reacquire the lock. Since notify() does
        not release the lock, its caller should.
        """
        if not self.locked():
            raise RuntimeError('cannot notify on un-acquired lock')
        self._notify(n)

    def _notify(self, n):
        idx = 0
        for fut in self._waiters:
            if idx >= n:
                break

            if not fut.done():
                idx += 1
                fut.set_result(False)

    def notify_all(self):
        """Wake up all tasks waiting on this condition. This method acts
        like notify(), but wakes up all waiting tasks instead of one. If the
        calling task has not acquired the lock when this method is called,
        a RuntimeError is raised.
        """

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Structure producers as: async with cond: ...; cond.notify_all()
  2. Ensure the notifying task is the one holding the lock (acquire it first)
  3. Consider asyncio.Event or Queue when lock ownership is hard to guarantee

Example fix

# before
async def producer(item):
    queue.append(item)
    cond.notify_all()  # RuntimeError

# after
async def producer(item):
    async with cond:
        queue.append(item)
        cond.notify_all()
Defensive patterns

Strategy: validation

Validate before calling

if not cond.locked():
    # notify() would raise; wrap in 'async with cond' first

Prevention

When it happens

Trigger: cond.notify() outside 'async with cond'; notify after the async-with body completed; producer task notifying a condition whose lock a consumer still holds.

Common situations: Porting threading code where notify is called loosely; splitting produce/consume across tasks without sharing the async with block; early returns that skip the context manager but still notify in cleanup.

Related errors


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