Explain Codes LogoExplain Codes Logo

Certificate verify failed: unable to get local issuer certificate

python
ssl
certificates
https
Anton ShumikhinbyAnton Shumikhin·Feb 1, 2025
TLDR

To tackle the SSL certificate errors in Python with the requests library, set the verify parameter pointing to your certificate:

requests.get('https://example.com', verify='/path/to/cert.pem')

For debugging purposes only, disable the verification (not for production usage):

requests.get('https://example.com', verify=False)

A common source of SSL errors is Python's lack of access to a verified list of CA certificates. The certifi package offers Python an up-to-date catalog of root certificates:

import requests import certifi response = requests.get('https://example.com', verify=certifi.where())

For Mac users, running "Install Certificates.command" often helps:

open /Applications/Python\ 3.x/Install\ Certificates.command

For broader knowledge and more comprehensive solutions, read on.

Mending the trust chain

Tying Python to the system's SSL certificates

Create a symlink between Python and your system's SSL certificates, enabling Python to trust your system's certificates:

ln -s /etc/ssl/certs/ca-certificates.crt /path/to/python/site-packages/certifi/cacert.pem

Updating the SSL certificates

Invoke "Install Certificates.command" on MacOS or refresh them via your package manager on Linux. Example:

sudo apt-get install --reinstall ca-certificates

Creating a secure context with Python's ssl module

Establish a default SSL context, specifying a CA file path:

import ssl import certifi import urllib.request context = ssl.create_default_context(cafile=certifi.where()) response = urllib.request.urlopen("https://example.com", context=context)

The /etc/ssl/ directory holds the SSL certificates for the system. Python’s ssl module, particularly on MacOS, doesn't always utilize the system's trusted certificates by default. Hence, Python needs a little hand-holding to locate the right trust store.

Python 3.6+ installations on MacOS have their own OpenSSL, which can result in trust issues because it may not include all the root certificates necessary to form a trust chain.

Securing HTTPS requests

A secure HTTPS request requires an accurate SSL context. Ensure the SSL context setup when fetching data with urllib.request or similar modules:

import ssl import urllib.request context = ssl._create_unverified_context() # Use only for testing; not recommended for production response = urllib.request.urlopen("https://example.com", context=context)

Knowing your security certificates

Understanding security certificates is pivotal in tackling SSL-related errors. Utilizing the certifi package is important as it provides the necessary root certificates to build SSL trust chains.

The "certificate verify failed" error signifies that Python's SSL module does not recognize the root certificates. Updating the certificate store on MacOS or establishing the correct SSL context can solve this error.

Contemplating the root certificate authority

The verification process involves tracing a chain of trust back to a root certificate authority (CA). If the CA that your server uses isn't part of your system’s list of trusted CAs, a verification error will pop up unless you supply the certificate explicitly.

A profound resolution

Case: Python cannot find the CA

If Python cannot find the Certificate Authority that approved the certificate being used, running "Install Certificates.command" or manually pointing to the correct certificate can help:

# Run this command on MacOS open /Applications/Python\ 3.x/Install\ Certificates.command
# Or, specify the CA bundle file in your code requests.get('https://example.com', verify='/path/to/ca-bundle.crt')

Case: Private or custom CA

If the certificates come from a private or custom CA, you need to include that CA's certificate in Python's trust store:

requests.get('https://example.com', verify='/path/to/custom-ca.pem')

Case: Seeking cross-platform compatibility

To ensure compatibility across platforms, let Python trust the certifi package:

requests.get('https://example.com', verify=certifi.where())