{"record":{"id":"755acd367bcab404","repo":"python/cpython","slug":"server-side-ssl-needs-a-valid-sslcontext","errorCode":null,"errorMessage":"Server side SSL needs a valid SSLContext","messagePattern":"Server side SSL needs a valid SSLContext","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/sslproto.py","lineNumber":49,"sourceCode":"class AppProtocolState(enum.Enum):\n    # This tracks the state of app protocol (https://git.io/fj59P):\n    #\n    #     INIT -cm-> CON_MADE [-dr*->] [-er-> EOF?] -cl-> CON_LOST\n    #\n    # * cm: connection_made()\n    # * dr: data_received()\n    # * er: eof_received()\n    # * cl: connection_lost()\n\n    STATE_INIT = \"STATE_INIT\"\n    STATE_CON_MADE = \"STATE_CON_MADE\"\n    STATE_EOF = \"STATE_EOF\"\n    STATE_CON_LOST = \"STATE_CON_LOST\"\n\n\ndef _create_transport_context(server_side, server_hostname):\n    if server_side:\n        raise ValueError('Server side SSL needs a valid SSLContext')\n\n    # Client side may pass ssl=True to use a default\n    # context; in that case the sslcontext passed is None.\n    # The default is secure for client connections.\n    # Python 3.4+: use up-to-date strong settings.\n    sslcontext = ssl.create_default_context()\n    if not server_hostname:\n        sslcontext.check_hostname = False\n    return sslcontext\n\n\ndef add_flowcontrol_defaults(high, low, kb):\n    if high is None:\n        if low is None:\n            hi = kb * 1024\n        else:\n            lo = low\n            hi = 4 * lo","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/sslproto.py#L31-L67","documentation":"Raised by _create_transport_context() in asyncio.sslproto as ValueError when server_side=True but no SSLContext was supplied. Unlike clients (where ssl=True can imply a default context), a server cannot use a default context because it must be configured with the server certificate and key, so asyncio refuses the combination.","triggerScenarios":"loop.create_server(proto_factory, host, port, ssl=True) or asyncio.start_server(handler, host, port, ssl=True) — i.e. passing the bare truthy value ssl=True on the server side.","commonSituations":"Copy-pasting client examples (where ssl=True is valid) into server code; enabling TLS on a server before provisioning certificates; test servers meant to use self-signed certs where the context was never constructed.","solutions":["Build a server context and pass it: ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER); ctx.load_cert_chain('cert.pem', 'key.pem'); then ssl=ctx in create_server/start_server.","For quick internal servers: ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) then load_cert_chain.","Never pass bare True for ssl on the server side; reserve ssl=True shorthand for client connections."],"exampleFix":"// before\nserver = await asyncio.start_server(handler, '0.0.0.0', 8443, ssl=True)\n# ValueError: Server side SSL needs a valid SSLContext\n\n// after\nctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\nctx.load_cert_chain('/etc/ssl/certs/server.pem', '/etc/ssl/private/server.key')\nserver = await asyncio.start_server(handler, '0.0.0.0', 8443, ssl=ctx)","handlingStrategy":"validation","validationCode":"import ssl\n\ndef server_ssl_context(certfile, keyfile):\n    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n    ctx.load_cert_chain(certfile, keyfile)\n    return ctx\n\nctx = server_ssl_context('server.crt', 'server.key')\nserver = await asyncio.start_server(handler, '0.0.0.0', 8443, ssl=ctx)","typeGuard":"def is_server_ssl_ctx(obj) -> bool:\n    return isinstance(obj, ssl.SSLContext)","tryCatchPattern":"try:\n    server = await asyncio.start_server(handler, host, port, ssl=ssl_arg)\nexcept ValueError as e:\n    if 'Server side SSL needs a valid SSLContext' in str(e):\n        raise SystemExit('configure ssl=SSLContext with load_cert_chain, not True')\n    raise","preventionTips":["Reserve ssl=True for client-side calls only.","Centralize context creation in one helper that loads cert and key.","Add a startup smoke test that constructs the server config and fails fast on bad ssl args."],"tags":["asyncio","ssl","tls","server","sslcontext","valueerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}