Introduction
Python on macOS (especially Python.org distributions) does not use the macOS system keychain for SSL certificate verification. Instead, it relies on the certifi package which bundles Mozilla's root certificates. If certifi is not installed or not configured, every HTTPS connection fails with CERTIFICATE_VERIFY_FAILED.
Symptoms
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)>ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failedpip installfails for all packages from PyPI- Works on Linux but fails on macOS with same code
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/urllib/request.py", line 219, in urlopen
return opener.open(url, timeout=timeout)
File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/urllib/request.py", line 519, in open
response = self._open(req, data)
File ".../urllib/request.py", line 541, in _open
return self._call_chain(self._handle_open, protocol, url)
File ".../ssl.py", line 517, in wrap_socket
context.load_verify_locations(cafile)
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: unable to get local issuer certificateCommon Causes
- Python.org macOS installer does not configure certificates by default
certifipackage not installedSSL_CERT_FILEenvironment variable pointing to wrong location- Corporate network with MITM proxy replacing certificates
- Using Homebrew Python without proper CA bundle
Step-by-Step Fix
- 1.Run the Python.org certificate installer:
- 2.```bash
- 3.# Python.org distributions include this script
- 4./Applications/Python\ 3.11/Install\ Certificates.command
# This runs: # pip install --upgrade certifi # ln -s /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/certifi/cacert.pem /Applications/Python\ 3.11/lib/python3.11/site-packages/certifi/cacert.pem ```
- 1.Install and configure certifi manually:
- 2.```bash
- 3.pip install --upgrade certifi
# Verify the certificate bundle exists python -c "import certifi; print(certifi.where())" # Expected: /Library/Frameworks/.../certifi/cacert.pem
# Set environment variable export SSL_CERT_FILE=$(python -c "import certifi; print(certifi.where())") ```
- 1.Configure at Python startup:
- 2.```python
- 3.import os
- 4.import certifi
os.environ['SSL_CERT_FILE'] = certifi.where()
import urllib.request response = urllib.request.urlopen('https://api.example.com') ```
- 1.Fix for Homebrew Python on macOS:
- 2.```bash
- 3.# Homebrew Python should use system certificates
- 4.brew install ca-certificates
- 5.brew postinstall openssl
# Verify python -c " import ssl ctx = ssl.create_default_context() print(f'CA file: {ctx.get_ca_certs()}') " ```
- 1.Handle corporate MITM proxy on macOS:
- 2.```bash
- 3.# Export corporate CA certificate from Keychain Access
- 4.# Then combine with certifi bundle
- 5.cat /path/to/corporate-ca.pem $(python -c "import certifi; print(certifi.where())") > /tmp/combined-ca.pem
- 6.export SSL_CERT_FILE=/tmp/combined-ca.pem
- 7.
`
Prevention
- Always run the
Install Certificates.commandafter installing Python.org distribution - Add
certifias a dependency in requirements.txt - Set
SSL_CERT_FILEin application startup code or environment config - For Docker on macOS, include CA certificates in the image
- Test SSL connections in CI on macOS runners to catch certificate issues early