python/cpython · error · ValueError
BoundedSemaphore released too many times
Error message
BoundedSemaphore released too many times
What it means
asyncio.BoundedSemaphore exists precisely to catch over-release: if release() would push the internal counter above the initial bound, it raises ValueError instead of silently growing. This surfaces unbalanced acquire/release logic that a plain Semaphore would hide.
Source
Thrown at Lib/asyncio/locks.py:461
# `fut` is now `done()` and not `cancelled()`.
return True
return False
class BoundedSemaphore(Semaphore):
"""A bounded semaphore implementation.
This raises ValueError in release() if it would increase the value
above the initial value.
"""
def __init__(self, value=1):
self._bound_value = value
super().__init__(value)
def release(self):
if self._value >= self._bound_value:
raise ValueError('BoundedSemaphore released too many times')
super().release()
class _BarrierState(enum.Enum):
FILLING = 'filling'
DRAINING = 'draining'
RESETTING = 'resetting'
BROKEN = 'broken'
class Barrier(mixins._LoopBoundMixin):
"""Asyncio equivalent to threading.Barrier
Implements a Barrier primitive.
Useful for synchronizing a fixed number of tasks at known synchronization
points. Tasks block on 'wait()' and are simultaneously awoken once they
have all made their call.View on GitHub (pinned to bc6749cc3b)
Solutions
- Remove duplicate releases; prefer 'async with sem:' which releases exactly once
- Release only on the success path of acquire: pair acquire/release in try/finally entered after acquire completes
- Audit with BoundedSemaphore during development to find the imbalance, even if plain Semaphore is used in production
Example fix
# before
async with sem:
...
finally:
sem.release() # second release -> ValueError
# after
async with sem: # releases exactly once
... Defensive patterns
Strategy: validation
Validate before calling
# BoundedSemaphore exposes _bound_value; check headroom before release
if sem._value >= sem._bound_value:
# release() would raise; skip or fix imbalance Try / catch
try:
sem.release()
except ValueError:
# over-release bug surfaced; log and fix acquire/release pairing Prevention
- Use 'async with sem:' so release happens exactly once
- Never pair the context manager with a manual release()
- Develop against BoundedSemaphore to catch imbalances early
When it happens
Trigger: Calling release() more times than acquire() succeeded; releasing in a finally block of a code path that never acquired; mixing manual release with 'async with sem' (which releases automatically).
Common situations: 'async with sem:' plus a manual sem.release() in cleanup; exception paths that release on tasks which timed out before acquiring; refactors that moved acquire() behind a condition but kept the unconditional release.
Related errors
- Lock is not acquired.
- cannot wait on un-acquired lock
- cannot notify on un-acquired lock
- Semaphore initial value must be >= 0
- {self!r} is bound to a different event loop
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/0e2cb2d5f6c97786.
Report an issue: GitHub.