python/cpython · error · ValueError
Semaphore initial value must be >= 0
Error message
Semaphore initial value must be >= 0
What it means
asyncio.Semaphore.__init__ validates that the initial counter value is non-negative; a negative value would make the semaphore permanently un-acquirable and its invariant (value >= 0) meaningless, so ValueError is raised at construction.
Source
Thrown at Lib/asyncio/locks.py:366
class Semaphore(_ContextManagerMixin, mixins._LoopBoundMixin):
"""A Semaphore implementation.
A semaphore manages an internal counter which is decremented by each
acquire() call and incremented by each release() call. The counter
can never go below zero; when acquire() finds that it is zero, it
blocks, waiting until some other thread calls release().
Semaphores also support the context management protocol.
The optional argument gives the initial value for the internal
counter; it defaults to 1. If the value given is less than 0,
ValueError is raised.
"""
def __init__(self, value=1):
if value < 0:
raise ValueError("Semaphore initial value must be >= 0")
self._waiters = None
self._value = value
def __repr__(self):
res = super().__repr__()
extra = 'locked' if self.locked() else f'unlocked, value:{self._value}'
if self._waiters:
extra = f'{extra}, waiters:{len(self._waiters)}'
return f'<{res[1:-1]} [{extra}]>'
def locked(self):
"""Returns True if semaphore cannot be acquired immediately."""
# Due to state, or FIFO rules (must allow others to run first).
return self._value == 0 or (
any(not w.cancelled() for w in (self._waiters or ())))
async def acquire(self):
"""Acquire a semaphore.View on GitHub (pinned to bc6749cc3b)
Solutions
- Clamp at the boundary: max(0, value)
- Validate configuration before constructing sync primitives; fail fast with a clear config error
- Treat 0 explicitly if 'block everything' is intended (0 is legal)
Example fix
# before sem = asyncio.Semaphore(cfg.max_concurrency - cfg.reserved) # can be < 0 # after value = max(0, cfg.max_concurrency - cfg.reserved) sem = asyncio.Semaphore(value)
Defensive patterns
Strategy: validation
Validate before calling
value = int(value)
if value < 0:
raise ValueError(f'concurrency must be >= 0, got {value}')
sem = asyncio.Semaphore(value) Type guard
def is_valid_semaphore_value(v) -> bool:
return isinstance(v, int) and v >= 0 Prevention
- Clamp config-derived limits with max(0, n)
- Validate numeric config at load time with clear errors
- Remember 0 is a legal 'block-all' value; negative never is
When it happens
Trigger: asyncio.Semaphore(-1) directly; computing the value from configuration/limits that can go negative (e.g. capacity - load); Semaphore(value=len(pool) - workers) with an empty pool.
Common situations: Config-derived concurrency limits; YAML/ENV-provided values parsed without bounds checking; arithmetic on sizes that underflow to negative on small deployments.
Related errors
- host and port was not specified and no sock specified
- parties must be >= 1
- Unimplemented ioctl request
- profiling_trace: Placeholder pattern not found in {js_path.n
- invalid action: {action!r}
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/74eee506d7d23138.
Report an issue: GitHub.