{"record":{"id":"b4a8a0373582a990","repo":"psf/requests","slug":"could-not-find-the-tls-key-file-invalid-path-co","errorCode":null,"errorMessage":"Could not find the TLS key file, invalid path: {conn.key_file}","messagePattern":"Could not find the TLS key file, invalid path: (.+?)","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"src/requests/adapters.py","lineNumber":361,"sourceCode":"        else:\n            conn.cert_reqs = \"CERT_NONE\"\n            conn.ca_certs = None\n            conn.ca_cert_dir = None\n\n        if cert:\n            if not isinstance(cert, basestring):\n                conn.cert_file = cert[0]\n                conn.key_file = cert[1]\n            else:\n                conn.cert_file = cert\n                conn.key_file = None\n            if conn.cert_file and not os.path.exists(conn.cert_file):\n                raise OSError(\n                    f\"Could not find the TLS certificate file, \"\n                    f\"invalid path: {conn.cert_file}\"\n                )\n            if conn.key_file and not os.path.exists(conn.key_file):\n                raise OSError(\n                    f\"Could not find the TLS key file, invalid path: {conn.key_file}\"\n                )\n\n    def build_response(self, req: PreparedRequest, resp: Any) -> Response:\n        \"\"\"Builds a :class:`Response <requests.Response>` object from a urllib3\n        response. This should not be called from user code, and is only exposed\n        for use when subclassing the\n        :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`\n\n        :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response.\n        :param resp: The urllib3 response object.\n        :rtype: requests.Response\n        \"\"\"\n        assert _is_prepared(req)\n        response = Response()\n\n        # Fallback to None if there's no status_code, for whatever reason.\n        response.status_code = getattr(resp, \"status\", None)  # type: ignore[assignment]","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/psf/requests/blob/8068356288978c4f54661ae6f95afe0e0831885e/src/requests/adapters.py#L343-L379","documentation":"Raised during cert_verify when a client certificate is supplied as a (cert, key) tuple and the resolved private key file path does not exist. After setting conn.key_file from the second tuple element, the code checks os.path.exists(conn.key_file); a missing key file aborts before the TLS handshake. The single-string cert form sets conn.key_file=None and so never triggers this branch.","triggerScenarios":"Produced when cert=(\"/path/client.crt\", \"/path/client.key\") is passed to a request or session and the key file (second element) does not exist. Only reachable via the tuple form, since the string form leaves key_file as None.","commonSituations":"Seen when the cert and key are stored in separate files and only one was deployed, when secret rotation updated the cert but not the key path, when the key file has restrictive permissions that effectively hide it, or when a path typo affects only the key element.","solutions":["Verify the key path exists with os.path.exists and that it is the second element of the cert tuple.","Check file permissions/ownership for the process running the request.","Ensure the secret volume mounts both files at the expected paths.","If cert and key are combined in one PEM, pass the single string form instead of a tuple.","In deployment, validate both halves of the cert pair in a startup probe."],"exampleFix":"# before\nsession.cert = (\"/etc/secrets/client.crt\", \"/etc/secrets/client.key\")  # key missing -> OSError\n\n# after\nimport os\ncrt, key = \"/etc/secrets/client.crt\", \"/etc/secrets/client.key\"\nassert os.path.exists(crt) and os.path.exists(key), \"cert or key missing\"\nsession.cert = (crt, key)","handlingStrategy":"validation","validationCode":"import os\n\ndef resolve_client_cert_tuple(cert):\n    \"\"\"For the (cert, key) tuple form, validate both files exist.\"\"\"\n    if isinstance(cert, (tuple, list)):\n        crt, key = cert\n        if not (os.path.exists(crt) and os.path.exists(key)):\n            raise FileNotFoundError(\n                f\"cert/key missing: cert={crt} key={key}\"\n            )\n        return (crt, key)\n    return cert  # string or None handled elsewhere\n\nsession.cert = resolve_client_cert_tuple(config[\"client_cert\"])","typeGuard":"import os\n\ndef has_valid_key_file(cert) -> bool:\n    \"\"\"True when cert is a tuple whose key file (2nd element) exists.\"\"\"\n    if isinstance(cert, (tuple, list)) and len(cert) == 2:\n        return os.path.exists(cert[1]) and os.access(cert[1], os.R_OK)\n    # string form sets key_file=None, so this branch is N/A\n    return True","tryCatchPattern":"try:\n    resp = session.get(url)\nexcept OSError as e:\n    if \"TLS key file\" in str(e):\n        raise RuntimeError(\n            f\"client key missing/unreadable: {session.cert}\"\n        ) from e\n    raise","preventionTips":["Always deploy the cert and key as a pair; validate both in a startup probe.\nGive the process user read permission on the key file.\nUse absolute paths to avoid working-directory ambiguity.\nIf cert+key share one PEM, use the string form to skip the key check."],"tags":["tls","client-cert","private-key","mutual-tls","config"],"backgroundTag":null,"analyzedSha":"8068356288978c4f54661ae6f95afe0e0831885e","analyzedAt":"2026-08-11T20:11:09.238Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}