{"id":"733b0597730e40df","repo":"aio-libs/aiohttp","slug":"cannot-initialize-a-tls-in-tls-connection-to-host","errorCode":null,"errorMessage":"Cannot initialize a TLS-in-TLS connection to host {req.url.host!s}:{req.url.port:d} through an underlying connection to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} [{type_err!s}]","messagePattern":"Cannot initialize a TLS-in-TLS connection to host (.+?):(.+?) through an underlying connection to an HTTPS proxy (.+?) ssl:(.+?) \\[(.+?)\\]","errorType":"exception","errorClass":"ClientConnectionError","httpStatus":null,"severity":"error","filePath":"aiohttp/connector.py","lineNumber":1480,"sourceCode":"                        except ServerFingerprintMismatch:\n                            tls_transport.close()\n                            if not self._cleanup_closed_disabled:\n                                self._cleanup_closed_transports.append(tls_transport)\n                            raise\n        except cert_errors as exc:\n            raise ClientConnectorCertificateError(req.connection_key, exc) from exc\n        except ssl_errors as exc:\n            raise ClientConnectorSSLError(req.connection_key, exc) from exc\n        except OSError as exc:\n            if exc.errno is None and isinstance(exc, asyncio.TimeoutError):\n                raise\n            raise client_error(req.connection_key, exc) from exc\n        except TypeError as type_err:\n            # Example cause looks like this:\n            # TypeError: transport <asyncio.sslproto._SSLProtocolTransport\n            # object at 0x7f760615e460> is not supported by start_tls()\n\n            raise ClientConnectionError(\n                \"Cannot initialize a TLS-in-TLS connection to host \"\n                f\"{req.url.host!s}:{req.url.port:d} through an underlying connection \"\n                f\"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} \"\n                f\"[{type_err!s}]\"\n            ) from type_err\n        else:\n            if tls_transport is None:\n                msg = \"Failed to start TLS (possibly caused by closing transport)\"\n                raise client_error(req.connection_key, OSError(msg))\n            tls_proto.connection_made(\n                tls_transport\n            )  # Kick the state machine of the new TLS protocol\n\n        return tls_transport, tls_proto\n\n    def _convert_hosts_to_addr_infos(\n        self, hosts: list[ResolveResult]\n    ) -> list[AddrInfoType]:","sourceCodeStart":1462,"sourceCodeEnd":1498,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/connector.py#L1462-L1498","documentation":"Raised inside _start_tls_connection() when `start_tls()` raises a TypeError because the underlying asyncio transport does not support being upgraded (the classic TLS-in-TLS limitation). aiohttp's `_warn_about_tls_in_tls` only suppresses the warning for uvloop, aiofastnet, or Python >=3.11; on older asyncio stdlib doing HTTPS-target-through-HTTPS-proxy, start_tls() rejects the transport and aiohttp wraps the TypeError as ClientConnectionError with a descriptive message.","triggerScenarios":"Sending an HTTPS request through an HTTPS (`https://...`) proxy on Python <3.11 using the default asyncio event loop (not uvloop, not aiofastnet). The plain-HTTP-proxy path is unaffected.","commonSituations":"Corporate HTTPS proxies (`https://proxy:443`) on legacy Python. CI pinned to Python 3.10. Switching from uvloop to default asyncio on an app that used HTTPS proxies.","solutions":["Upgrade to Python 3.11+ where stdlib asyncio supports TLS-in-TLS (bpo-44011).","Switch the event loop to uvloop (or aiofastnet) which supports TLS-in-TLS on older Python.","Use an HTTP (`http://`) proxy instead of an HTTPS proxy where possible - that path uses plain TCP then TLS, no nested TLS.","Apply the documented monkeypatch (see aiohttp proxy docs / discussion #6044) only as a last resort."],"exampleFix":"# before (Python 3.10, default asyncio)\nasync with session.get('https://target', proxy='https://proxy:443') as r: ...\n# after\nimport uvloop\nuvloop.install()  # before creating the event loop\n# or upgrade to Python 3.11+","handlingStrategy":"validation","validationCode":"import sys\n\ndef supports_tls_in_tls() -> bool:\n    return sys.version_info >= (3, 11)","typeGuard":null,"tryCatchPattern":"from aiohttp import ClientConnectionError\ntry:\n    await session.get('https://target', proxy='https://proxy:443')\nexcept ClientConnectionError as e:\n    if 'TLS-in-TLS' in str(e):\n        # switch to uvloop, upgrade Python, or use an http:// proxy\n        ...\n    raise","preventionTips":["Prefer http:// proxies over https:// proxies when possible.","On legacy Python, install uvloop before constructing the event loop.","Detect the configuration at startup and fail fast with a clear message."],"tags":["connector","ssl","proxy","tls-in-tls","event-loop","client"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}