aio-libs/aiohttp · error · TypeError

ssl should be SSLContext, Fingerprint, or bool, got {ssl!r}

Error message

ssl should be SSLContext, Fingerprint, or bool, got {ssl!r} instead.

What it means

Raised in ClientSession.__init__ (client.py:340) as a TypeError when the ssl argument is not one of the allowed types: ssl.SSLContext, aiohttp.Fingerprint, or bool. SSL_ALLOWED_TYPES is (ssl.SSLContext, bool, Fingerprint) when ssl is importable, else (bool,). Passing anything else (str, dict, tuple, int) is rejected up front to fail fast.

Source

Thrown at aiohttp/client.py:340

        fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8",
        middlewares: Sequence[ClientMiddlewareType] = (),
        ssl_shutdown_timeout: _SENTINEL | None | float = sentinel,
    ) -> None:
        # We initialise _connector to None immediately, as it's referenced in __del__()
        # and could cause issues if an exception occurs during initialisation.
        self._connector: BaseConnector | None = None
        if base_url is None or isinstance(base_url, URL):
            self._base_url: URL | None = base_url
            self._base_url_origin = None if base_url is None else base_url.origin()
        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",

View on GitHub (pinned to c0ef574e29)

Solutions

  1. To use a cert file, build a context: ssl=ssl.create_default_context(cafile='ca.pem').
  2. To disable verification for a trusted host, pass ssl=False (not ssl=0 or a string).
  3. To pin a server key, pass ssl=aiohttp.Fingerprint(b'...').

Example fix

# before
session = aiohttp.ClientSession(ssl='server.pem')

# after
import ssl
ctx = ssl.create_default_context(cafile='server.pem')
session = aiohttp.ClientSession(ssl=ctx)
Defensive patterns

Strategy: type-guard

Validate before calling

import ssl
from aiohttp import Fingerprint

def make_ssl(v):
    if isinstance(v, (ssl.SSLContext, Fingerprint, bool)):
        return v
    if isinstance(v, str):  # treat as cert path
        ctx = ssl.create_default_context(cafile=v)
        return ctx
    raise TypeError('ssl must be SSLContext, Fingerprint, or bool')

Type guard

def is_valid_ssl(v) -> bool:
    import ssl
    from aiohttp import Fingerprint
    return isinstance(v, (ssl.SSLContext, Fingerprint, bool))

Try / catch

try:
    session = aiohttp.ClientSession(ssl=ssl_value)
except TypeError:
    ssl_value = ssl.create_default_context(cafile=str(ssl_value))
    session = aiohttp.ClientSession(ssl=ssl_value)

Prevention

When it happens

Trigger: ClientSession(ssl='certfile.pem') or ssl={'verify': True} or ssl=1 — any value whose type is not SSLContext/Fingerprint/bool. Note a path string is NOT accepted; you must build an SSLContext.

Common situations: Passing a certificate file path string instead of an SSLContext built from it; passing an int where a bool was expected; passing a config dict from another library; disabling verification incorrectly.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/fc39e8898db05ba7.json. Report an issue: GitHub.