{"record":{"id":"620e4c99bd881b6d","repo":"python/cpython","slug":"limit-cannot-be-0","errorCode":null,"errorMessage":"Limit cannot be <= 0","messagePattern":"Limit cannot be <= 0","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/streams.py","lineNumber":420,"sourceCode":"\n    def __del__(self, warnings=warnings):\n        if not self._transport.is_closing():\n            if self._loop.is_closed():\n                warnings.warn(\"loop is closed\", ResourceWarning)\n            else:\n                self.close()\n                warnings.warn(f\"unclosed {self!r}\", ResourceWarning)\n\nclass StreamReader:\n\n    _source_traceback = None\n\n    def __init__(self, limit=_DEFAULT_LIMIT, loop=None):\n        # The line length limit is  a security feature;\n        # it also doubles as half the buffer limit.\n\n        if limit <= 0:\n            raise ValueError('Limit cannot be <= 0')\n\n        self._limit = limit\n        if loop is None:\n            self._loop = events.get_event_loop()\n        else:\n            self._loop = loop\n        self._buffer = bytearray()\n        self._eof = False    # Whether we're done.\n        self._waiter = None  # A future used by _wait_for_data()\n        self._exception = None\n        self._transport = None\n        self._paused = False\n        if self._loop.get_debug():\n            self._source_traceback = format_helpers.extract_stack(\n                sys._getframe(1))\n\n    def __repr__(self):\n        info = ['StreamReader']","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/streams.py#L402-L438","documentation":"ValueError raised by StreamReader.__init__ when the limit argument is zero or negative. The limit is both the readline/readuntil separator length bound and half the flow-control buffer size, so a non-positive value is meaningless and rejected immediately at construction.","triggerScenarios":"StreamReader(limit=0), StreamReader(limit=-1), or asyncio.open_connection/start_server(..., limit=n) with n <= 0; typically the value comes from a config value, CLI flag, or arithmetic that evaluated to zero.","commonSituations":"A 'max line length' setting defaulting to 0 meaning 'unset'; computing limit as a difference or percentage that collapses to 0; passing a buffer-size knob meant for something else into the streams limit parameter.","solutions":["Pass a positive limit (default is 64 KiB, _DEFAULT_LIMIT); choose it deliberately given readline/readuntil semantics","Validate/derive config values at startup: limit = max(1, configured) only if a sane default is intended, otherwise fail fast with a clear config error","If you meant 'no line limit', pick a large explicit value rather than 0 — the parameter is not an on/off switch"],"exampleFix":"// before\nreader, writer = await asyncio.open_connection(host, port, limit=cfg.max_line_bytes)  # cfg value 0\n\n// after\nif cfg.max_line_bytes <= 0:\n    raise ValueError(f'max_line_bytes must be > 0, got {cfg.max_line_bytes}')\nreader, writer = await asyncio.open_connection(host, port, limit=cfg.max_line_bytes)","handlingStrategy":"validation","validationCode":"def checked_limit(value: int) -> int:\n    if not isinstance(value, int) or value <= 0:\n        raise ValueError(f'stream limit must be a positive int, got {value!r}')\n    return value","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Validate stream/buffer settings once at startup with clear config-error messages","Treat a 0 in config as 'unset' and substitute the documented default explicitly, never pass it through","Remember limit bounds readline/readuntil separator length and half the buffer — size it from protocol requirements"],"tags":["asyncio","streams","validation","config"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}