aio-libs/aiohttp · error · ValueError
timeout parameter cannot be of {type(timeout)} type, please
Error message
timeout parameter cannot be of {type(timeout)} type, please use 'timeout=ClientTimeout(...)' What it means
Raised as a ValueError in ClientSession.__init__ (client.py:349-353) when the timeout argument is neither the sentinel, None, nor a ClientTimeout instance. aiohttp requires all per-session and per-request timeouts to be expressed as a ClientTimeout dataclass so connect/read/total/sock_connect/sock_read can be configured independently. Passing a bare float/int (the pre-3.x style) is rejected because there is no way to know which timeout dimension it should clamp.
Source
Thrown at aiohttp/client.py:350
else:
self._base_url = URL(base_url)
self._base_url_origin = self._base_url.origin()
assert self._base_url.absolute, "Only absolute URLs are supported"
if self._base_url is not None and not self._base_url.path.endswith("/"):
raise ValueError("base_url must have a trailing '/'")
if not isinstance(ssl, SSL_ALLOWED_TYPES):
raise TypeError(
"ssl should be SSLContext, Fingerprint, or bool, "
f"got {ssl!r} instead."
)
loop = asyncio.get_running_loop()
if timeout is sentinel or timeout is None:
timeout = ClientTimeout()
if not isinstance(timeout, ClientTimeout):
raise ValueError(
f"timeout parameter cannot be of {type(timeout)} type, "
"please use 'timeout=ClientTimeout(...)'",
)
self._timeout = timeout
if ssl_shutdown_timeout is not sentinel:
warnings.warn(
"The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0",
DeprecationWarning,
stacklevel=2,
)
if connector is None:
connector = TCPConnector(ssl_shutdown_timeout=ssl_shutdown_timeout)
# Initialize these three attrs before raising any exception,
# they are used in __del__
self._connector = connector
self._loop = loopView on GitHub (pinned to d9aaf697c2)
Solutions
- Replace any numeric timeout with timeout=ClientTimeout(total=<seconds>) (or set sock_read=/sock_connect= for finer control).
- Import ClientTimeout: from aiohttp import ClientTimeout.
- Pass timeout=None (not a number) when you want aiohttp's default timeout rather than a custom one.
- Audit code paths that forward timeout=**kwargs verbatim and coerce values into ClientTimeout at the boundary.
Example fix
# before session = aiohttp.ClientSession(timeout=30) await session.get(url, timeout=10) # after from aiohttp import ClientTimeout session = aiohttp.ClientSession(timeout=ClientTimeout(total=30)) await session.get(url, timeout=ClientTimeout(total=10))
Defensive patterns
Strategy: type-guard
Validate before calling
from aiohttp import ClientTimeout
def coerce_timeout(t):
if t is None or isinstance(t, ClientTimeout):
return t
if isinstance(t, (int, float)):
return ClientTimeout(total=t)
raise TypeError(f'timeout must be ClientTimeout or number, got {type(t)}') Type guard
from aiohttp import ClientTimeout
def is_client_timeout(v) -> bool:
return v is None or isinstance(v, ClientTimeout) Try / catch
try:
session = aiohttp.ClientSession(timeout=my_timeout)
except ValueError as e:
if 'timeout parameter cannot be' in str(e):
# fallback: build a ClientTimeout from the offending value if numeric
session = aiohttp.ClientSession(timeout=ClientTimeout(total=float(my_timeout)))
else:
raise Prevention
- Centralize timeout construction behind one helper that always returns ClientTimeout.
- Never forward raw **kwargs containing timeout into aiohttp without coercion.
- Statically check with mypy using aiohttp's type stubs for the timeout parameter.
When it happens
Trigger: Constructing ClientSession(timeout=30) or session.get(url, timeout=10) with a numeric value instead of ClientTimeout(total=30). Also passing timeout=0 or a string, a timedelta, or any non-ClientTimeout object. Note: timeout=None is explicitly accepted (client.py:347) and means 'use the default ClientTimeout()', so None does not trigger this.
Common situations: Migrating from aiohttp 2.x or the requests library where timeout=float is idiomatic. Copying examples from outdated tutorials. Wrapping the timeout in a variable that conditionally becomes a number. Confusing the ws_connect timeout (which historically accepted a float and still emits a DeprecationWarning) with the request/session timeout.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Connection timeout to host {req.url}
- Session and connector have to use same event loop
- Inheritance class {cls.__name__} from ClientSession is forbi
- data and json parameters can not be used at the same time
- None is not allowed as login value
AI-assisted analysis of aio-libs/aiohttp@d9aaf697c2 (2026-08-06).
Data as JSON: /api/errors/92a6113ea023e31c.
Report an issue: GitHub.