{"record":{"id":"17e6dc9e8359dcce","repo":"python/cpython","slug":"ssl-shutdown-timeout-is-only-meaningful-with-ssl","errorCode":null,"errorMessage":"ssl_shutdown_timeout is only meaningful with ssl","messagePattern":"ssl_shutdown_timeout is only meaningful with ssl","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/base_events.py","lineNumber":1110,"sourceCode":"            # already-connected socket was passed or when only a port\n            # is given.  To avoid this error, you can pass\n            # server_hostname='' -- this will bypass the hostname\n            # check.  (This also means that if host is a numeric\n            # IP/IPv6 address, we will attempt to verify that exact\n            # address; this will probably fail, but it is possible to\n            # create a certificate for a specific IP address, so we\n            # don't judge it here.)\n            if not host:\n                raise ValueError('You must set server_hostname '\n                                 'when using ssl without a host')\n            server_hostname = host\n\n        if ssl_handshake_timeout is not None and not ssl:\n            raise ValueError(\n                'ssl_handshake_timeout is only meaningful with ssl')\n\n        if ssl_shutdown_timeout is not None and not ssl:\n            raise ValueError(\n                'ssl_shutdown_timeout is only meaningful with ssl')\n\n        if sock is not None:\n            _check_ssl_socket(sock)\n\n        if happy_eyeballs_delay is not None and interleave is None:\n            # If using happy eyeballs, default to interleave addresses by family\n            interleave = 1\n\n        if host is not None or port is not None:\n            if sock is not None:\n                raise ValueError(\n                    'host/port and sock can not be specified at the same time')\n\n            infos = await self._ensure_resolved(\n                (host, port), family=family,\n                type=socket.SOCK_STREAM, proto=proto, flags=flags, loop=self)\n            if not infos:","sourceCodeStart":1092,"sourceCodeEnd":1128,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/base_events.py#L1092-L1128","documentation":"Raised by create_connection when ssl_shutdown_timeout is given but ssl is not. This timeout bounds the TLS shutdown (close_notify) phase of the connection; like the handshake timeout it is meaningful only for TLS, so asyncio rejects it on plaintext connections.","triggerScenarios":"Calling loop.create_connection(proto, host, port, ssl_shutdown_timeout=5.0) with ssl unset (None). The argument exists only in newer Pythons; combined with conditional TLS it is easy to leak into a plaintext call.","commonSituations":"Config-driven client builders that forward a TLS settings object as **kwargs and a code path that sets ssl=None; disabling TLS against a local test server while keeping the shutdown timeout setting.","solutions":["Pass ssl_shutdown_timeout only in the branch that also passes ssl=ctx.","Strip TLS-only keys from kwargs when TLS is disabled: kwargs.pop('ssl_shutdown_timeout', None).","Keep ssl, server_hostname, and both ssl timeouts as one atomic kwargs group."],"exampleFix":"// before\nawait loop.create_connection(proto, h, p, ssl_shutdown_timeout=5)  # no ssl\n\n// after\nawait loop.create_connection(proto, h, p, ssl=ctx, ssl_shutdown_timeout=5)","handlingStrategy":"validation","validationCode":"tls_kwargs = {}\nif ctx is not None:\n    tls_kwargs.update(ssl=ctx, ssl_shutdown_timeout=5)","typeGuard":null,"tryCatchPattern":"try:\n    await loop.create_connection(proto, h, p, ssl_shutdown_timeout=5)\nexcept ValueError:\n    await loop.create_connection(proto, h, p, ssl=ssl.create_default_context(),\n                                 ssl_shutdown_timeout=5)","preventionTips":["Group ssl_shutdown_timeout with ssl in config validation: reject one without the other.","When disabling TLS at runtime, clear the whole TLS kwargs block together.","Add a config schema check that ssl-adjacent keys require ssl=true."],"tags":["asyncio","tls","ssl","timeout","validation"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}