pypa/pip · critical · SSLMissingError

ssl-missing

ssl-missing

Error message

Failed to establish a secure connection for {url}

What it means

Raised as SSLMissingError in PipSession.request when the underlying request to an HTTPS URL fails with an ImportError whose message mentions 'ssl'. That means the running Python interpreter was built without the _ssl/OpenSSL C extension, so HTTPS is impossible.

Solutions

  1. Reinstall or rebuild Python with OpenSSL support (install libssl-dev/openssl-devel and reconfigure/recompile).
  2. Use an official CPython distribution that bundles SSL support.
  3. Verify with 'python -c "import ssl"' that the interpreter can load _ssl.
  4. As a last resort only, point pip at an HTTP index (insecure, not recommended).
Defensive patterns

Strategy: validation

Validate before calling

def python_has_ssl() -> bool:
    try:
        import ssl  # noqa: F401
        return True
    except ImportError:
        return False

# assert python_has_ssl()

Prevention

When it happens

Trigger: Any HTTPS index/download request when Python's _ssl module is unavailable; e.g. a stripped or custom-built CPython lacking OpenSSL linkage, or a broken Python distribution where _ssl.pyd/.so failed to import.

Common situations: Minimal Docker/base images with hand-compiled Python missing libssl-dev; broken Python installs after an OS openssl upgrade relocated the shared lib; embedded Python distributions.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/05dc1acea9c2e012. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/network/session.py:548

    def request(self, method: str, url: str, *args: Any, **kwargs: Any) -> Response:  # type: ignore[override]
        # Allow setting a default timeout on a session
        kwargs.setdefault("timeout", self.timeout)
        # Allow setting a default proxies on a session
        kwargs.setdefault("proxies", self.proxies)

        # Dispatch the actual request
        try:
            return super().request(method, url, *args, **kwargs)
        except (requests.ConnectionError, requests.Timeout) as e:
            request = getattr(e, "request", None)
            failed_url = getattr(request, "url", None) or url
            raise_connection_error(e, url=failed_url, timeout=kwargs["timeout"])
        except ImportError as e:
            if "ssl" in str(e).lower():
                # Unfortunately, if this TLS error was the result of a redirect from
                # a HTTP to a HTTPS url, we don't know what the final url was.
                raise SSLMissingError(redact_auth_from_url(url))
            raise

View on GitHub (pinned to f399c37189)