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 = loop

View on GitHub (pinned to d9aaf697c2)

Solutions

  1. Replace any numeric timeout with timeout=ClientTimeout(total=<seconds>) (or set sock_read=/sock_connect= for finer control).
  2. Import ClientTimeout: from aiohttp import ClientTimeout.
  3. Pass timeout=None (not a number) when you want aiohttp's default timeout rather than a custom one.
  4. 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

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

Related errors


AI-assisted analysis of aio-libs/aiohttp@d9aaf697c2 (2026-08-06). Data as JSON: /api/errors/92a6113ea023e31c. Report an issue: GitHub.