pypa/pip · error · OSError

Could not find the TLS key file, invalid path: {conn.key_fil

Error message

Could not find the TLS key file, invalid path: {conn.key_file}

What it means

HTTPAdapter.cert_verify raises OSError when client-certificate authentication is requested with a cert tuple whose second element (the private key file path) does not exist. conn.key_file is checked with os.path.exists only when a separate key file is supplied.

Source

Thrown at src/pip/_vendor/requests/adapters.py:361

        else:
            conn.cert_reqs = "CERT_NONE"
            conn.ca_certs = None
            conn.ca_cert_dir = None

        if cert:
            if not isinstance(cert, basestring):
                conn.cert_file = cert[0]
                conn.key_file = cert[1]
            else:
                conn.cert_file = cert
                conn.key_file = None
            if conn.cert_file and not os.path.exists(conn.cert_file):
                raise OSError(
                    f"Could not find the TLS certificate file, "
                    f"invalid path: {conn.cert_file}"
                )
            if conn.key_file and not os.path.exists(conn.key_file):
                raise OSError(
                    f"Could not find the TLS key file, invalid path: {conn.key_file}"
                )

    def build_response(self, req: PreparedRequest, resp: Any) -> Response:
        """Builds a :class:`Response <requests.Response>` object from a urllib3
        response. This should not be called from user code, and is only exposed
        for use when subclassing the
        :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`

        :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response.
        :param resp: The urllib3 response object.
        :rtype: requests.Response
        """
        assert _is_prepared(req)
        response = Response()

        # Fallback to None if there's no status_code, for whatever reason.
        response.status_code = getattr(resp, "status", None)  # type: ignore[assignment]

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Confirm the private key file exists at the given path and is readable.
  2. Use an absolute path for the key file.
  3. Ensure the key file is provisioned in the runtime (mount/secret).
  4. If cert and key live in one PEM, pass a single string (cert='/path/combined.pem') instead of a tuple.

Example fix

# before
requests.get(url, cert=('/etc/ssl/c.crt', '/wrong/client.key'))

# after
requests.get(url, cert=('/etc/ssl/c.crt', '/etc/ssl/c.key'))
Defensive patterns

Strategy: validation

Validate before calling

import os
key_path = cert[1] if isinstance(cert, (tuple, list)) and len(cert) == 2 else None
if key_path and not os.path.exists(key_path):
    raise FileNotFoundError(f'client key not found: {key_path}')
requests.get(url, cert=cert)

Try / catch

try:
    resp = requests.get(url, cert=cert)
except OSError as e:
    if 'TLS key file' in str(e):
        raise RuntimeError(f'missing client key: {e}') from e
    raise

Prevention

When it happens

Trigger: Calling requests with cert=('/path/client.crt','/path/client.key') where client.key is missing; a scalar cert string sets key_file=None and will not hit this path, so this is specific to the two-element tuple form.

Common situations: Key file not deployed alongside the cert; path typo for the key; permissions/mount issues in containers; key stored in a different directory than expected.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/1fdecdf23c500445.json. Report an issue: GitHub.