python/cpython · critical · RuntimeError

Python ssl module is not available

Error message

Python ssl module is not available

What it means

A RuntimeError raised by loop.start_tls() when the interpreter was built without a working ssl module (asyncio's optional ssl import is None). start_tls exists purely to negotiate TLS, so with no ssl module it cannot proceed and reports unavailability rather than crashing deeper in the stack.

Solutions

  1. Reinstall or rebuild Python against OpenSSL (e.g. apt install libssl-dev before pyenv install).
  2. Use a distribution/binary that ships the ssl module; verify with python -c "import ssl".
  3. Gate TLS code paths on ssl availability so non-TLS operation still works.

Example fix

# before
transport = await loop.start_tls(raw_tp, proto, ctx)  # RuntimeError

# after
import sys
if 'ssl' not in sys.modules or sys.modules.get('ssl') is None:
    raise RuntimeError('TLS unavailable: this Python lacks the ssl module')
transport = await loop.start_tls(raw_tp, proto, ctx)
Defensive patterns

Strategy: validation

Validate before calling

try:
    import ssl
except ImportError:
    raise RuntimeError('TLS unavailable: Python built without the ssl module')

Try / catch

try:
    tp = await loop.start_tls(raw_tp, proto, ctx)
except RuntimeError as e:
    if 'ssl module is not available' not in str(e):
        raise
    raise RuntimeError('rebuild Python with OpenSSL support') from e

Prevention

When it happens

Trigger: Calling await loop.start_tls(transport, protocol, ctx) on a Python built with the ssl extension disabled (misconfigured build, --without-ssl, or a platform where OpenSSL dev headers were missing at build time).

Common situations: Minimal/stripped Python builds in tiny containers or embedded distributions; distro Pythons compiled without OpenSSL linkage; CI images that trimmed development libraries before building Python.

Understand the failure class

Related errors


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

Appendix: source

Thrown at Lib/asyncio/base_events.py:1340

                await proto.drain()
                total_sent += read
        finally:
            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)

View on GitHub (pinned to bc6749cc3b)