python/cpython · error · TypeError

Socket cannot be of type SSLSocket

Error message

Socket cannot be of type SSLSocket

What it means

_check_ssl_socket is called by asyncio transports/servers (e.g. loop.create_connection and loop.create_server) whenever a pre-made sock is supplied together with an ssl context. asyncio implements TLS itself via ssl protocols and requires a plain socket; passing an already-wrapped ssl.SSLSocket would double-handshake and corrupt the protocol, so it raises TypeError immediately.

Source

Thrown at Lib/asyncio/base_events.py:207

            # stop it.
            return
    futures._get_loop(fut).stop()


if hasattr(socket, 'TCP_NODELAY'):
    def _set_nodelay(sock):
        if (sock.family in {socket.AF_INET, socket.AF_INET6} and
                sock.type == socket.SOCK_STREAM and
                sock.proto == socket.IPPROTO_TCP):
            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
else:
    def _set_nodelay(sock):
        pass


def _check_ssl_socket(sock):
    if ssl is not None and isinstance(sock, ssl.SSLSocket):
        raise TypeError("Socket cannot be of type SSLSocket")


class _SendfileFallbackProtocol(protocols.Protocol):
    def __init__(self, transp):
        if not isinstance(transp, transports._FlowControlMixin):
            raise TypeError("transport should be _FlowControlMixin instance")
        self._transport = transp
        self._proto = transp.get_protocol()
        self._should_resume_reading = transp.is_reading()
        self._should_resume_writing = transp._protocol_paused
        transp.pause_reading()
        transp.set_protocol(self)
        if self._should_resume_writing:
            self._write_ready_fut = self._transport._loop.create_future()
        else:
            self._write_ready_fut = None

    async def drain(self):

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass the raw, unwrapped socket and the SSLContext: loop.create_connection(proto, sock=raw_sock, ssl=sslctx) — asyncio does the handshake asynchronously.
  2. If the socket is already TLS-wrapped by other code, pass ssl=None and treat the stream as already secure (and avoid blocking wrap_socket in async code).
  3. In async code, replace sslctx.wrap_socket with asyncio's ssl= parameter or await loop.start_tls(...) for upgrading in place.

Example fix

# before
wrapped = ssl_ctx.wrap_socket(raw_sock, server_hostname='example.com')
reader, writer = await asyncio.open_connection(sock=wrapped, ssl=ssl_ctx)
# TypeError: Socket cannot be of type SSLSocket

# after
reader, writer = await asyncio.open_connection(
    sock=raw_sock, ssl=ssl_ctx, server_hostname='example.com')
Defensive patterns

Strategy: type-guard

Validate before calling

import socket, ssl

def check_not_ssl_socket(sock):
    if isinstance(sock, ssl.SSLSocket):
        raise TypeError('pass the raw socket plus ssl=SSLContext to asyncio')
    return sock

Type guard

import ssl

def is_plain_socket(sock) -> bool:
    return not (ssl and isinstance(sock, ssl.SSLSocket))

Try / catch

try:
    reader, writer = await asyncio.open_connection(sock=sock, ssl=ctx)
except TypeError as e:
    if 'SSLSocket' in str(e):
        # unwrap is impossible; fix the caller: pass raw sock + ssl=ctx
        raise RuntimeError('do not pre-wrap sockets; pass ssl=SSLContext') from None

Prevention

When it happens

Trigger: s = sslctx.wrap_socket(raw_sock) followed by await loop.create_connection(proto, sock=s, ssl=sslctx); similarly create_server(..., sock=wrapped) or sock_* helpers handed an SSLSocket. Also occurs when a socket obtained from some library already performs TLS (e.g. a tunnel library) and is then forwarded to asyncio with ssl set.

Common situations: Upgrading plain-socket code to TLS by wrapping the socket manually (the intuitive but wrong approach); libraries that hand out connected SSLSocket objects that are then fed to asyncio; mixing blocking ssl module usage with asyncio's async TLS layer.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/bd94d219bd41af40. Report an issue: GitHub.