{"record":{"id":"1e34f2e7566d9b59","repo":"aio-libs/aiohttp","slug":"total-timeout-must-be-a-positive-number-or-none-to","errorCode":null,"errorMessage":"total timeout must be a positive number or None to disable, got 0. Using 0 to disable timeouts is no longer supported, use None instead.","messagePattern":"total timeout must be a positive number or None to disable, got 0\\. Using 0 to disable timeouts is no longer supported, use None instead\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/client_reqrep.py","lineNumber":125,"sourceCode":"    def __post_init__(self) -> None:\n        # Ensure total is never lower than a more specific timeout, otherwise\n        # the latter would be silently capped by total and rendered useless.\n        # total=None means the user explicitly disabled the total timeout.\n        if self.total is None:\n            return\n        object.__setattr__(\n            self,\n            \"total\",\n            max(\n                self.total,\n                self.connect or 0,\n                self.sock_read or 0,\n                self.sock_connect or 0,\n            ),\n        )\n\n        if self.total == 0:\n            raise ValueError(\n                \"total timeout must be a positive number or None to disable, \"\n                \"got 0. Using 0 to disable timeouts is no longer supported, \"\n                \"use None instead.\"\n            )\n\n\ndef _gen_default_accept_encoding() -> str:\n    encodings = [\n        \"gzip\",\n        \"deflate\",\n    ]\n    if HAS_BROTLI:\n        encodings.append(\"br\")\n    if HAS_ZSTD:\n        encodings.append(\"zstd\")\n    return \", \".join(encodings)\n\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/client_reqrep.py#L107-L143","documentation":"Raised by ClientTimeout.__post_init__ when the 'total' timeout resolves to exactly 0. Historically, total=0 meant 'disable timeout', but aiohttp now requires None for that; a literal 0 (or all sub-timeouts being 0 with total defaulting to 0) is treated as a misconfiguration and raises ValueError. Note the dataclass first bumps total to the max of itself and any sub-timeout, so total becomes 0 only if total and every sub-timeout are 0/None.","triggerScenarios":"Constructing ClientTimeout(total=0); or ClientTimeout(total=0, connect=0, sock_read=0) where all resolve to 0; or passing total=0 implicitly through a session/request. The check in __post_init__ fires at construction time, not at request time.","commonSituations":"Code ported from an older aiohttp version where total=0 disabled timeouts; config loaded from a file/env where 0 was the legacy 'off' sentinel; copy-paste of a snippet targeting an older API.","solutions":["Pass total=None to disable the overall timeout: ClientTimeout(total=None).","If you want a small timeout, use a positive number: ClientTimeout(total=30).","Audit config sources (env vars, YAML) that map 'disable' to 0 and remap them to None.","Upgrade guides: search the codebase for 'ClientTimeout(total=0' and replace."],"exampleFix":"# before\ntimeout = ClientTimeout(total=0)  # ValueError\n\n# after — disable total timeout explicitly\ntimeout = ClientTimeout(total=None)","handlingStrategy":"validation","validationCode":"from aiohttp import ClientTimeout\n\ndef safe_timeout(total=None, **kw):\n    # normalize legacy 0 (disable) to None\n    if total == 0:\n        total = None\n    for k, v in list(kw.items()):\n        if v == 0:\n            kw[k] = None\n    return ClientTimeout(total=total, **kw)","typeGuard":"def is_valid_total(total) -> bool:\n    return total is None or (isinstance(total, (int, float)) and total > 0)","tryCatchPattern":"from aiohttp import ClientTimeout\n\ntry:\n    timeout = ClientTimeout(total=cfg_total)\nexcept ValueError as e:\n    if 'got 0' in str(e):\n        timeout = ClientTimeout(total=None)  # migrate legacy disable semantics\n    else:\n        raise","preventionTips":["Treat 0 as an invalid timeout in all config schemas; use None for 'disabled'.","Run a grep for 'total=0' across the codebase when upgrading aiohttp.","Document the None-vs-0 distinction in your config reference."],"tags":["timeout","configuration","client","version-migration"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}