python/cpython · error · TypeError
sslcontext is expected to be an instance of ssl.SSLContext,
Error message
sslcontext is expected to be an instance of ssl.SSLContext, got {sslcontext!r} What it means
A TypeError raised by loop.start_tls() when the sslcontext argument is not an ssl.SSLContext instance. start_tls uses the context to configure certificates, protocols and verification; passing anything else (a boolean like ssl.CERT_REQUIRED, a string path, or None) is rejected with the offending value shown.
Source
Thrown at Lib/asyncio/base_events.py:1343
if total_sent > 0 and hasattr(file, 'seek'):
file.seek(offset + total_sent)
await proto.restore()
async def start_tls(self, transport, protocol, sslcontext, *,
server_side=False,
server_hostname=None,
ssl_handshake_timeout=None,
ssl_shutdown_timeout=None):
"""Upgrade transport to TLS.
Return a new transport that *protocol* should start using
immediately.
"""
if ssl is None:
raise RuntimeError('Python ssl module is not available')
if not isinstance(sslcontext, ssl.SSLContext):
raise TypeError(
f'sslcontext is expected to be an instance of ssl.SSLContext, '
f'got {sslcontext!r}')
if not getattr(transport, '_start_tls_compatible', False):
raise TypeError(
f'transport {transport!r} is not supported by start_tls()')
waiter = self.create_future()
ssl_protocol = sslproto.SSLProtocol(
self, protocol, sslcontext, waiter,
server_side, server_hostname,
ssl_handshake_timeout=ssl_handshake_timeout,
ssl_shutdown_timeout=ssl_shutdown_timeout,
call_connection_made=False)
# Pause early so that "ssl_protocol.data_received()" doesn't
# have a chance to get called before "ssl_protocol.connection_made()".
transport.pause_reading()View on GitHub (pinned to bc6749cc3b)
Solutions
- Create a real context: ctx = ssl.create_default_context() (client) or ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) with load_cert_chain (server).
- Set verify options on the context (ctx.verify_mode = ssl.CERT_REQUIRED), not as the argument itself.
- Type-check the variable early if it comes from dynamic configuration.
Example fix
# before transport = await loop.start_tls(tp, proto, ssl.CERT_REQUIRED) # TypeError # after ctx = ssl.create_default_context() ctx.check_hostname = True transport = await loop.start_tls(tp, proto, ctx)
Defensive patterns
Strategy: type-guard
Validate before calling
import ssl assert isinstance(ctx, ssl.SSLContext), 'start_tls requires an ssl.SSLContext'
Type guard
import ssl
def is_ssl_context(obj: object) -> bool:
return isinstance(obj, ssl.SSLContext) Try / catch
try:
tp = await loop.start_tls(raw_tp, proto, ctx)
except TypeError as e:
if 'ssl.SSLContext' not in str(e):
raise
ctx = ssl.create_default_context()
tp = await loop.start_tls(raw_tp, proto, ctx) Prevention
- Always construct contexts via ssl.create_default_context() or SSLContext(PROTOCOL_TLS_*).
- Set verify_mode/check_hostname on the context object, never pass ssl constants as the context.
- Type-annotate sslcontext parameters as ssl.SSLContext so static checkers catch misuse.
When it happens
Trigger: Calling loop.start_tls(transport, protocol, ssl.CERT_REQUIRED) — passing a verify-mode constant instead of a context; passing a PEM filename; passing None expecting a default context (there is none).
Common situations: Confusing ssl module constants with contexts (CERT_REQUIRED etc. are ints); porting code that used ssl.wrap_socket's looser arguments; forgetting ssl.create_default_context() when building the call.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- server_hostname is only meaningful with ssl
- You must set server_hostname when using ssl without a host
- ssl_handshake_timeout is only meaningful with ssl
- ssl_shutdown_timeout is only meaningful with ssl
- Socket cannot be of type SSLSocket
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/741f69adc170f3be.
Report an issue: GitHub.