aio-libs/aiohttp · error · ValueError
total timeout must be a positive number or None to disable,
Error message
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.
What it means
Raised as ValueError in ClientTimeout.__post_init__ when the 'total' field equals exactly 0. Historically some users passed total=0 to mean 'disable timeout'; aiohttp now requires total=None for that, because 0 is ambiguous with 'immediately time out'. The post_init also clamps total to be >= any specific timeout, so a negative or zero total after clamping triggers this.
Source
Thrown at aiohttp/client_reqrep.py:125
def __post_init__(self) -> None:
# Ensure total is never lower than a more specific timeout, otherwise
# the latter would be silently capped by total and rendered useless.
# total=None means the user explicitly disabled the total timeout.
if self.total is None:
return
object.__setattr__(
self,
"total",
max(
self.total,
self.connect or 0,
self.sock_read or 0,
self.sock_connect or 0,
),
)
if self.total == 0:
raise ValueError(
"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."
)
def _gen_default_accept_encoding() -> str:
encodings = [
"gzip",
"deflate",
]
if HAS_BROTLI:
encodings.append("br")
if HAS_ZSTD:
encodings.append("zstd")
return ", ".join(encodings)
View on GitHub (pinned to c0ef574e29)
Solutions
- Pass total=None to disable the overall timeout.
- Pass a positive float (e.g. 30.0) for a real timeout ceiling.
- Audit dynamic config: coerce 0 to None before constructing ClientTimeout.
Example fix
# before client_timeout = aiohttp.ClientTimeout(total=0) # after client_timeout = aiohttp.ClientTimeout(total=None) # disable total timeout
Defensive patterns
Strategy: validation
Validate before calling
def make_timeout(total):
if total == 0:
total = None # treat 0 as disable
return aiohttp.ClientTimeout(total=total) Type guard
def is_valid_total(total) -> bool:
return total is None or (isinstance(total, (int, float)) and total > 0) Prevention
- Never pass total=0; use None to disable.
- Validate dynamic config: coerce 0 -> None before constructing ClientTimeout.
- Add a unit test that asserts ClientTimeout(total=0) raises.
When it happens
Trigger: Fires at line 124-129 when self.total is not None and resolves to 0 after max() with connect/sock_read/sock_connect. Common when constructing ClientTimeout(total=0) or when all specific timeouts are 0/None and total is 0.
Common situations: Migrating from older aiohttp or requests where timeout=0 meant disable; copy-pasted configs; building ClientTimeout from dynamic config where a 0 slips in.
Related errors
- Connection timeout to host {url}
- timeout parameter cannot be of {type} type, please use 'time
- Digest auth error: Unsupported Quality of Protection (qop) v
- {url}
- aiohttp only supports http(s) proxies (got: {proxy.scheme!r}
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/1e34f2e7566d9b59.json.
Report an issue: GitHub.