aio-libs/aiohttp · error · RuntimeError

SSL is not supported.

Error message

SSL is not supported.

What it means

Raised by GunicornWebWorker._create_ssl_context() when the ssl module is None, i.e. the running Python interpreter was compiled without OpenSSL support (`ssl` failed to import, caught at the top of worker.py). It is only reached when gunicorn is configured with SSL (cfg.is_ssl True) and the worker tries to build the SSLContext.

Solutions

  1. Use a Python distribution built with SSL — the official python:3.x images, or install openssl/openssl-dev and ca-certificates on Alpine before building Python.
  2. Verify in the same environment with `python -c "import ssl; print(ssl.OPENSSL_VERSION)`.
  3. If you did not intend TLS, remove the certfile/keyfile/ssl options from the gunicorn config so cfg.is_ssl is False.
  4. Terminate TLS at a reverse proxy (nginx, a load balancer) and run the aiohttp worker without SSL.

Example fix

// before (Alpine, no openssl)
FROM python:3.12-alpine
RUN pip install aiohttp
# gunicorn --certfile server.crt ... -> raises

// after
FROM python:3.12-alpine
RUN apk add --no-cache openssl ca-certificates
RUN pip install aiohttp
# or use the slim debian image which ships SSL:
FROM python:3.12-slim
Defensive patterns

Strategy: validation

Validate before calling

import ssl as _ssl
if _ssl is None:
    raise SystemExit('This Python has no ssl module; install OpenSSL or use a different image')

Type guard

def ssl_available() -> bool:
    import sys
    return sys.modules.get('ssl') is not None and sys.modules['ssl'] is not None

Try / catch

# surfaced as RuntimeError at worker boot; resolve in the environment, not in code.
# Before launching gunicorn:
import ssl
assert ssl.OPENSSL_VERSION

Prevention

When it happens

Trigger: Configuring gunicorn with --certfile/--ssl-ciphers (or a config that sets is_ssl) while running a Python build where `import ssl` fails. Common on minimal/self-compiled CPython without libssl dev headers, or some Alpine images missing openssl.

Common situations: Alpine/musl images without openssl installed; a custom-compiled Python without --with-openssl; a stripped/embedded Python distribution; CI base image that omits ca-certificates/openssl.

Understand the failure class

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/4f3363f1a535bf97. Report an issue: GitHub.

Appendix: source

Thrown at aiohttp/worker.py:223

        self.cfg.worker_int(self)

        # wakeup closing process
        self._notify_waiter_done()

    def handle_abort(self, sig: int, frame: FrameType | None) -> None:
        self.alive = False
        self.exit_code = 1
        self.cfg.worker_abort(self)
        sys.exit(1)

    @staticmethod
    def _create_ssl_context(cfg: Any) -> "SSLContext":
        """Creates SSLContext instance for usage in asyncio.create_server.

        See ssl.SSLSocket.__init__ for more details.
        """
        if ssl is None:  # pragma: no cover
            raise RuntimeError("SSL is not supported.")

        ctx = ssl.SSLContext(cfg.ssl_version)
        ctx.load_cert_chain(cfg.certfile, cfg.keyfile)
        ctx.verify_mode = cfg.cert_reqs
        if cfg.ca_certs:
            ctx.load_verify_locations(cfg.ca_certs)
        if cfg.ciphers:
            ctx.set_ciphers(cfg.ciphers)
        return ctx

    def _get_valid_log_format(self, source_format: str) -> str:
        if source_format == self.DEFAULT_GUNICORN_LOG_FORMAT:
            return self.DEFAULT_AIOHTTP_LOG_FORMAT
        elif re.search(r"%\([^\)]+\)", source_format):
            raise ValueError(
                "Gunicorn's style options in form of `%(name)s` are not "
                "supported for the log formatting. Please use aiohttp's "
                "format specification to configure access log formatting: "

View on GitHub (pinned to d041d4d0fd)