psf/requests · error · OSError

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

Error message

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

What it means

Raised in HTTPAdapter.cert_verify when a client certificate was supplied via the `cert` parameter but the certificate file path does not exist on disk. requests sets conn.cert_file from either the string form (cert='path.pem') or the first element of the tuple form (cert=('cert.pem','key.pem')) and validates existence before handing the connection to urllib3, failing fast instead of producing an opaque SSL handshake error.

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 414f0513c3)

Solutions

  1. Verify the path exists (os.path.exists) and use an absolute path for the client certificate
  2. Fix the cert tuple order — it must be (cert_file, key_file), not (key, cert)
  3. In containers/cron, confirm the cert is mounted/deployed at the configured path
  4. If the key is embedded in the same PEM as the cert, pass a single string path instead of a tuple

Example fix

# before
requests.get(url, cert=('client.crt', 'client.key'))  # relative, cwd-dependent

# after
from pathlib import Path
cert_dir = Path(__file__).parent / 'certs'
requests.get(url, cert=(str(cert_dir/'client.crt'), str(cert_dir/'client.key')))
Defensive patterns

Strategy: validation

Validate before calling

import os
cert_file = cert[0] if isinstance(cert, tuple) else cert
if not os.path.isfile(cert_file):
    raise FileNotFoundError(f"Client TLS certificate not found: {cert_file}")

Try / catch

try:
    resp = session.get(url, cert=(cert_file, key_file))
except OSError as e:
    raise RuntimeError(f"Client cert path invalid: {cert_file}") from e

Prevention

When it happens

Trigger: requests.get(url, cert='client.pem') or cert=('client.crt','client.key') where the cert path is wrong or relative to a different working directory; Session.cert set to a stale path. Checked at src/requests/adapters.py:355-359 whenever cert is truthy.

Common situations: Relative cert paths that break when the script runs from a different cwd (cron, systemd, containers); certs mounted into containers at a different path than configured; rotated/expired mTLS certs deleted during renewal; config files referencing another developer's home directory.

Related errors


AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31). Data as JSON: /data/errors/f9bbfd4c08da1f98.json. Report an issue: GitHub ↗.