{"record":{"id":"52b37b6db52f59af","repo":"RustPython/RustPython","slug":"parties-must-be-1","errorCode":null,"errorMessage":"parties must be >= 1","messagePattern":"parties must be >= 1","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/locks.py","lineNumber":488,"sourceCode":"    FILLING = 'filling'\n    DRAINING = 'draining'\n    RESETTING = 'resetting'\n    BROKEN = 'broken'\n\n\nclass Barrier(mixins._LoopBoundMixin):\n    \"\"\"Asyncio equivalent to threading.Barrier\n\n    Implements a Barrier primitive.\n    Useful for synchronizing a fixed number of tasks at known synchronization\n    points. Tasks block on 'wait()' and are simultaneously awoken once they\n    have all made their call.\n    \"\"\"\n\n    def __init__(self, parties):\n        \"\"\"Create a barrier, initialised to 'parties' tasks.\"\"\"\n        if parties < 1:\n            raise ValueError('parties must be >= 1')\n\n        self._cond = Condition() # notify all tasks when state changes\n\n        self._parties = parties\n        self._state = _BarrierState.FILLING\n        self._count = 0       # count tasks in Barrier\n\n    def __repr__(self):\n        res = super().__repr__()\n        extra = f'{self._state.value}'\n        if not self.broken:\n            extra += f', waiters:{self.n_waiting}/{self.parties}'\n        return f'<{res[1:-1]} [{extra}]>'\n\n    async def __aenter__(self):\n        # wait for the barrier reaches the parties number\n        # when start draining release and return index of waited task\n        return await self.wait()","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/asyncio/locks.py#L470-L506","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nbarrier = asyncio.Barrier(num_workers)  # num_workers == 0 at runtime\n\n# after\nif num_workers < 1:\n    raise ValueError(f\"num_workers must be >= 1, got {num_workers}\")\nbarrier = asyncio.Barrier(num_workers)","handlingStrategy":"validation","validationCode":"def check_parties(n) -> None:\n    if not isinstance(n, int) or isinstance(n, bool) or n < 1:\n        raise ValueError(f\"Barrier parties must be an int >= 1, got {n!r}\")\n\ncheck_parties(num_workers)\nbarrier = asyncio.Barrier(num_workers)","typeGuard":"def is_valid_parties(n) -> bool:\n    return isinstance(n, int) and not isinstance(n, bool) and n >= 1","tryCatchPattern":null,"preventionTips":["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"],"tags":["asyncio","barrier","synchronization","argument-validation","constructor","python"],"backgroundTag":"invalid-argument-value","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}