{"record":{"id":"fc39e8898db05ba7","repo":"aio-libs/aiohttp","slug":"ssl-should-be-sslcontext-fingerprint-or-bool-go","errorCode":null,"errorMessage":"ssl should be SSLContext, Fingerprint, or bool, got {ssl!r} instead.","messagePattern":"ssl should be SSLContext, Fingerprint, or bool, got (.+?) instead\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/client.py","lineNumber":340,"sourceCode":"        fallback_charset_resolver: _CharsetResolver = lambda r, b: \"utf-8\",\n        middlewares: Sequence[ClientMiddlewareType] = (),\n        ssl_shutdown_timeout: _SENTINEL | None | float = sentinel,\n    ) -> None:\n        # We initialise _connector to None immediately, as it's referenced in __del__()\n        # and could cause issues if an exception occurs during initialisation.\n        self._connector: BaseConnector | None = None\n        if base_url is None or isinstance(base_url, URL):\n            self._base_url: URL | None = base_url\n            self._base_url_origin = None if base_url is None else base_url.origin()\n        else:\n            self._base_url = URL(base_url)\n            self._base_url_origin = self._base_url.origin()\n            assert self._base_url.absolute, \"Only absolute URLs are supported\"\n        if self._base_url is not None and not self._base_url.path.endswith(\"/\"):\n            raise ValueError(\"base_url must have a trailing '/'\")\n\n        if not isinstance(ssl, SSL_ALLOWED_TYPES):\n            raise TypeError(\n                \"ssl should be SSLContext, Fingerprint, or bool, \"\n                f\"got {ssl!r} instead.\"\n            )\n\n        loop = asyncio.get_running_loop()\n\n        if timeout is sentinel or timeout is None:\n            timeout = ClientTimeout()\n        if not isinstance(timeout, ClientTimeout):\n            raise ValueError(\n                f\"timeout parameter cannot be of {type(timeout)} type, \"\n                \"please use 'timeout=ClientTimeout(...)'\",\n            )\n        self._timeout = timeout\n\n        if ssl_shutdown_timeout is not sentinel:\n            warnings.warn(\n                \"The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0\",","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/client.py#L322-L358","documentation":"Raised by ClientSession.__init__ when the ssl argument is not an SSLContext, Fingerprint, or bool (the union SSL_ALLOWED_TYPES). aiohttp needs a concrete TLS configuration object; arbitrary values cannot be coerced. Unlike requests, a file path string is not accepted.","triggerScenarios":"Calling ClientSession(ssl='cert.pem'), ClientSession(ssl='TLSv1'), or passing a dict, int, or None where None is not the default sentinel. The isinstance(ssl, SSL_ALLOWED_TYPES) check fails.","commonSituations":"Migrating from requests where verify='cert.pem' / cert='path' strings are valid. Storing ssl config in a YAML/dict and passing the dict directly. Confusing the ssl flag with a cipher or protocol name string.","solutions":["Pass a bool for default verification: ClientSession(ssl=True) (or False to disable verification).","Load an SSLContext: ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile='ca.pem'); ClientSession(ssl=ctx).","Pass a Fingerprint for certificate pinning: Fingerprint(hashlib.sha256(der).digest())."],"exampleFix":"// before\nsession = ClientSession(ssl='cert.pem')\n// after\nimport ssl as _ssl\nctx = _ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile='cert.pem')\nsession = ClientSession(ssl=ctx)","handlingStrategy":"type-guard","validationCode":"import ssl as _ssl\nfrom aiohttp import TCPConnector\nfrom aiohttp.typedefs import PathLike  # if available\n\nSSL_ALLOWED = (bool, _ssl.SSLContext)\n# Note: Fingerprint is also allowed; import from aiohttp\n\ndef to_ssl_arg(value):\n    if isinstance(value, bool) or isinstance(value, _ssl.SSLContext):\n        return value\n    raise TypeError('ssl must be bool or SSLContext')","typeGuard":"import ssl as _ssl\nfrom aiohttp import Fingerprint\n\ndef is_valid_ssl(v) -> bool:\n    return isinstance(v, (bool, _ssl.SSLContext, Fingerprint))","tryCatchPattern":"try:\n    session = ClientSession(ssl=value)\nexcept TypeError as e:\n    if 'ssl should be' in str(e):\n        raise SystemExit('Provide an SSLContext, Fingerprint, or bool for ssl')\n    raise","preventionTips":["Always build an ssl.SSLContext from cafile paths rather than passing paths.","Keep TLS configuration in a single helper that returns one of the three allowed types.","Type-annotate ssl params as 'SSLContext | Fingerprint | bool' so static checkers catch misuse."],"tags":["ssl","client-session","type-validation","tls"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}