{"record":{"id":"4555c0be2901eb35","repo":"psf/requests","slug":"could-not-find-a-suitable-tls-ca-certificate-bundl","errorCode":null,"errorMessage":"Could not find a suitable TLS CA certificate bundle, invalid path: {cert_loc}","messagePattern":"Could not find a suitable TLS CA certificate bundle, invalid path: (.+?)","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"src/requests/adapters.py","lineNumber":332,"sourceCode":"        :param conn: The urllib3 connection object associated with the cert.\n        :param url: The requested URL.\n        :param verify: Either a boolean, in which case it controls whether we verify\n            the server's TLS certificate, or a string, in which case it must be a path\n            to a CA bundle to use\n        :param cert: The SSL certificate to verify.\n        \"\"\"\n        if url.lower().startswith(\"https\") and verify:\n            cert_loc = None\n\n            # Allow self-specified cert location.\n            if verify is not True:\n                cert_loc = verify\n\n            if not cert_loc:\n                cert_loc = DEFAULT_CA_BUNDLE_PATH\n\n            if not cert_loc or not os.path.exists(cert_loc):\n                raise OSError(\n                    f\"Could not find a suitable TLS CA certificate bundle, \"\n                    f\"invalid path: {cert_loc}\"\n                )\n\n            conn.cert_reqs = \"CERT_REQUIRED\"\n\n            if not os.path.isdir(cert_loc):\n                conn.ca_certs = cert_loc\n            else:\n                conn.ca_cert_dir = cert_loc\n        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]","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/psf/requests/blob/8068356288978c4f54661ae6f95afe0e0831885e/src/requests/adapters.py#L314-L350","documentation":"Raised during cert_verify when an HTTPS request is made with verify enabled (True or a path) but no readable CA certificate bundle exists at the resolved location. The library resolves cert_loc from an explicit verify path, then falls back to DEFAULT_CA_BUNDLE_PATH (certifi); if the final path is empty or os.path.exists returns False, it raises OSError. This is a pre-connection guard so that urllib3 never proceeds without a trust store.","triggerScenarios":"Produced when verify=True and the bundled certifi CA file is missing from the install (corrupt or stripped install), or when verify is set to a user-supplied path string that does not exist on the filesystem. Also when DEFAULT_CA_BUNDLE_PATH points at a file removed by an OS package cleanup or a slimmed container image.","commonSituations":"Happens in distroless/alpine images where certifi data files were pruned, in frozen apps (PyInstaller) that did not include the certifi cacert.pem via --add-data, in air-gapped envs where verify points to an internal CA bundle path that differs across hosts, and after a broken pip install that left certifi partially installed.","solutions":["If using verify=True: reinstall certifi (pip install --force-reinstall certifi) so DEFAULT_CA_BUNDLE_PATH resolves.","If verify=<path>: confirm the path exists and is readable with os.path.exists/os.access before passing it.","For PyInstaller/frozen apps: include the certifi bundle, e.g. --add-data \"$(python -m certifi);certifi\" and reference it via verify=certifi.where().","For container images: install ca-certificates and certifi in the final stage, or COPY the bundle into a stable path and pass verify=that path.","As a temporary diagnostic, set verify=False only to confirm the error source; never leave it disabled for production TLS."],"exampleFix":"# before\nrequests.get(\"https://example.com\", verify=\"/etc/ssl/missing-bundle.pem\")  # -> OSError\n\n# after\nimport certifi\nrequests.get(\"https://example.com\", verify=certifi.where())","handlingStrategy":"validation","validationCode":"import os\nimport certifi\n\ndef resolve_ca_bundle(verify):\n    \"\"\"Return a verified-existing CA bundle path, or True for the default.\"\"\"\n    if verify is True or verify is None:\n        path = certifi.where()\n    elif isinstance(verify, str):\n        path = verify\n    else:\n        return verify  # False\n    if not path or not os.path.exists(path):\n        raise FileNotFoundError(f\"CA bundle not found: {path}\")\n    return path\n\n# usage\nrequests.get(url, verify=resolve_ca_bundle(verify_arg))","typeGuard":"import os\n\ndef is_valid_ca_bundle(verify) -> bool:\n    if verify is True or verify is None:\n        import certifi\n        return os.path.exists(certifi.where())\n    if verify is False:\n        return True\n    if isinstance(verify, str):\n        return os.path.exists(verify) and os.access(verify, os.R_OK)\n    return False","tryCatchPattern":"try:\n    resp = requests.get(url, verify=verify_path)\nexcept OSError as e:\n    if \"CA certificate bundle\" in str(e):\n        # fall back to certifi, or fail loudly\n        import certifi\n        resp = requests.get(url, verify=certifi.where())\n    else:\n        raise","preventionTips":["In containers, install ca-certificates and certifi in the final image.","For frozen apps (PyInstaller), bundle cacert.pem and pass verify=certifi.where().","Validate verify paths with os.path.exists at startup, not at first request.","Never delete certifi data files when trimming site-packages."],"tags":["tls","certificates","ca-bundle","certifi","config"],"backgroundTag":null,"analyzedSha":"8068356288978c4f54661ae6f95afe0e0831885e","analyzedAt":"2026-08-11T20:11:09.238Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}