RustPython/RustPython · error · ValueError
parties must be >= 1
Error message
parties must be >= 1
What it means
asyncio.Barrier (Python 3.11+) requires at least one participating task. Its constructor validates the parties argument immediately and raises ValueError('parties must be >= 1') when parties is 0 or negative, because a barrier that never fills would block forever. The value fixes how many wait() calls must arrive before all waiting tasks are released simultaneously.
Source
Thrown at Lib/asyncio/locks.py:488
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.
"""
def __init__(self, parties):
"""Create a barrier, initialised to 'parties' tasks."""
if parties < 1:
raise ValueError('parties must be >= 1')
self._cond = Condition() # notify all tasks when state changes
self._parties = parties
self._state = _BarrierState.FILLING
self._count = 0 # count tasks in Barrier
def __repr__(self):
res = super().__repr__()
extra = f'{self._state.value}'
if not self.broken:
extra += f', waiters:{self.n_waiting}/{self.parties}'
return f'<{res[1:-1]} [{extra}]>'
async def __aenter__(self):
# wait for the barrier reaches the parties number
# when start draining release and return index of waited task
return await self.wait()View on GitHub (pinned to aaeab4f754)
Solutions
- Validate the count before constructing: if num_workers < 1, raise a clear configuration error naming the offending value
- If 0 participants means 'no synchronization needed', skip creating and awaiting the barrier entirely for that run
- Only as a last resort clamp with max(1, parties) when 0 genuinely denotes a single-participant barrier
Example fix
# before
barrier = asyncio.Barrier(num_workers) # num_workers == 0 at runtime
# after
if num_workers < 1:
raise ValueError(f"num_workers must be >= 1, got {num_workers}")
barrier = asyncio.Barrier(num_workers) Defensive patterns
Strategy: validation
Validate before calling
def check_parties(n) -> None:
if not isinstance(n, int) or isinstance(n, bool) or n < 1:
raise ValueError(f"Barrier parties must be an int >= 1, got {n!r}")
check_parties(num_workers)
barrier = asyncio.Barrier(num_workers) Type guard
def is_valid_parties(n) -> bool:
return isinstance(n, int) and not isinstance(n, bool) and n >= 1 Prevention
- Derive barrier parties from a validated worker-count config, never from len() of a possibly-empty collection
- Treat parties < 1 as a configuration bug: fail at startup with a message naming the value and its source
- When 0 participants is legal in your domain, branch around the barrier instead of clamping the count
When it happens
Trigger: Constructing asyncio.Barrier(0) or asyncio.Barrier(-n); passing a dynamically computed worker count that can be 0, e.g. asyncio.Barrier(len(tasks)) when the task list is empty; threading.Barrier code ported to asyncio where the parties argument was optional or defaulted.
Common situations: Fan-out/fan-in stages whose participant list can legitimately be empty under certain configs; worker-pool sizes read from user config or environment variables without bounds checking; refactors that changed a 'default to 1' behavior into an explicit count.
Related errors
- {self!r} is bound to a different event loop
- Invalid address: must be None or {self._address}
- Invalid sign. The first value in the tuple should be an int
- unsupported whence value
- "raw" argument must be readable.
AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17).
Data as JSON: /api/errors/52b37b6db52f59af.
Report an issue: GitHub.