{"record":{"id":"262a1668f5ad1bfd","repo":"python/cpython","slug":"ssl-argument-must-be-an-sslcontext-or-none","errorCode":null,"errorMessage":"ssl argument must be an SSLContext or None","messagePattern":"ssl argument must be an SSLContext or None","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/base_events.py","lineNumber":1572,"sourceCode":"            ssl_shutdown_timeout=None,\n            start_serving=True):\n        \"\"\"Create a TCP server.\n\n        The host parameter can be a string, in that case the TCP server is\n        bound to host and port.\n\n        The host parameter can also be a sequence of strings and in that\n        case the TCP server is bound to all hosts of the sequence.  If\n        a host appears multiple times (possibly indirectly e.g. when\n        hostnames resolve to the same IP address), the server is only bound\n        once to that host.\n\n        Return a Server object which can be used to stop the service.\n\n        This method is a coroutine.\n        \"\"\"\n        if isinstance(ssl, bool):\n            raise TypeError('ssl argument must be an SSLContext or None')\n\n        if ssl_handshake_timeout is not None and ssl is None:\n            raise ValueError(\n                'ssl_handshake_timeout is only meaningful with ssl')\n\n        if ssl_shutdown_timeout is not None and ssl is None:\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 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            if reuse_address is None:","sourceCodeStart":1554,"sourceCodeEnd":1590,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/base_events.py#L1554-L1590","documentation":"Raised by create_server() when the ssl argument is a bool (True/False). Historically ssl=True was interpreted as a default context; that footgun was removed, so ssl must be an ssl.SSLContext or None — True does not mean 'default context' anymore.","triggerScenarios":"loop.create_server(factory, host, port, ssl=True) or ssl=False; any code passing a boolean flag copied from an old tutorial.","commonSituations":"Pre-3.11-era code or copy-pasted examples using ssl=True; wrapping the ssl parameter in a feature flag (ssl=use_tls) where use_tls is a bool.","solutions":["Pass ssl=ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) (plus load_cert_chain) for a TLS server","Pass ssl=None (or omit it) for plaintext","If a bool flag drives TLS in your config, branch on it and select the context yourself"],"exampleFix":"# before\nserver = await loop.create_server(factory, '0.0.0.0', 443, ssl=True)\n\n# after\nctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\nctx.load_cert_chain('cert.pem', 'key.pem')\nserver = await loop.create_server(factory, '0.0.0.0', 443, ssl=ctx)","handlingStrategy":"type-guard","validationCode":"import ssl\nassert ssl is None or isinstance(ssl, ssl.SSLContext), 'ssl must be SSLContext or None'","typeGuard":"import ssl\ndef is_server_ssl(v: object) -> TypeGuard[ssl.SSLContext | None]:\n    return v is None or isinstance(v, ssl.SSLContext)","tryCatchPattern":null,"preventionTips":["Never pass booleans as the ssl argument; build contexts explicitly","Name the config field tls_context, not ssl_enabled, so a bool cannot leak in"],"tags":["asyncio","tls","server","api-misuse"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}