psf/requests · error · OSError

Could not find the TLS certificate file, invalid path

Error message

Could not find the TLS certificate file, invalid path: {conn.cert_file}

What it means

Raised during cert_verify when a client certificate is supplied (cert=...) but the resolved certificate file path does not exist on disk. The cert argument may be a single path string or a (cert, key) tuple; conn.cert_file is set from it and then os.path.exists is checked. A missing file aborts before the TLS handshake so the failure is surfaced as a config error rather than an opaque SSL error.

Solutions

  1. Check the path exists with os.path.exists before passing it as cert; resolve it to an absolute path first.
  2. Confirm the file is readable by the process user (permissions, mount, volume).
  3. For containerized apps: verify the secret/configmap is mounted at the exact path and the mount is not read-only-missing.
  4. If using a tuple, ensure the cert file is the first element and the key the second.
  5. In CI, fail fast by asserting the cert path during startup health checks rather than at first request.

Example fix

# before
session.cert = "/etc/secrets/client.crt"  # file absent -> OSError

# after
import os
cert_path = os.path.abspath("/etc/secrets/client.crt")
assert os.path.exists(cert_path), f"client cert missing: {cert_path}"
session.cert = cert_path
Defensive patterns

Strategy: validation

Validate before calling

import os

def resolve_client_cert(cert):
    """Validate cert arg; return it unchanged if the file(s) exist."""
    if cert is None:
        return None
    if isinstance(cert, str):
        if not os.path.exists(cert):
            raise FileNotFoundError(f"client cert not found: {cert}")
    elif isinstance(cert, (tuple, list)):
        for p in cert:
            if not os.path.exists(p):
                raise FileNotFoundError(f"cert file not found: {p}")
    else:
        raise TypeError(f"unsupported cert type: {type(cert)}")
    return cert

session.cert = resolve_client_cert(config["client_cert"])

Type guard

import os

def is_valid_client_cert(cert) -> bool:
    if cert is None:
        return True
    if isinstance(cert, str):
        return os.path.exists(cert) and os.access(cert, os.R_OK)
    if isinstance(cert, (tuple, list)) and len(cert) == 2:
        return all(os.path.exists(p) and os.access(p, os.R_OK) for p in cert)
    return False

Try / catch

try:
    resp = session.get(url)
except OSError as e:
    if "TLS certificate file" in str(e):
        # re-check the path, log, and surface a clear config error
        raise RuntimeError(f"client cert path invalid: {session.cert}") from e
    raise

Prevention

When it happens

Trigger: Triggered by passing cert="/path/client.pem" (or cert=("/path/client.crt", "/path/client.key")) where the first element does not exist, in calls to request/get/post or when configuring an HTTPAdapter/Session with a cert. Fires for both the single-string and tuple forms once conn.cert_file is non-empty.

Common situations: Common with mTLS clients where the cert path is environment-specific and the value was hardcoded, when a deployment mounts secrets at a different path than the code expects, when relative paths are resolved against an unexpected working directory, or after secret rotation replaced the file with a new name.

Understand the failure class

Related errors


AI-assisted analysis of psf/requests@8068356288 (2026-08-11). Data as JSON: /api/errors/f9bbfd4c08da1f98. Report an issue: GitHub.

Appendix: source

Thrown at src/requests/adapters.py:356

            if not os.path.isdir(cert_loc):
                conn.ca_certs = cert_loc
            else:
                conn.ca_cert_dir = cert_loc
        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
        """

View on GitHub (pinned to 8068356288)