Fix ssl.SSLCertVerificationError: certificate verify failed in Python HTTPS Requests

beginner🐍 Python2026-03-20| Python 3.6+, macOS / Linux / Windows, requests library or urllib

Error Message

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)
#python#ssl#requests#https#certificate

TL;DR

Python can't verify the server's SSL certificate against its trusted CA bundle. Pick the fix that matches your situation:

  • macOS: run the Install Certificates.command script that ships with Python.
  • Any OS with requests: upgrade certifi and you're likely done.
  • Corporate/self-signed cert: add the CA certificate to your trust store.

Skip the verify=False shortcut. It silently strips all SSL protection β€” and opens you to man-in-the-middle attacks in production.

What triggers this error

Every HTTPS request Python makes goes through a certificate check. Python compares the server's cert against a bundle of trusted Certificate Authorities (CAs). That check fails for a few common reasons:

  • Python's CA bundle is missing or stale β€” very common on fresh macOS installs.
  • The server uses a self-signed certificate or a private corporate CA.
  • A corporate proxy (Zscaler, Charles, Fiddler) is doing SSL inspection and presenting its own cert.
  • Python's ssl module can't reach the system CA store.

The full traceback looks like this:

requests.exceptions.SSLError: HTTPSConnectionPool(host='example.com', port=443): Max retries exceeded with url: /
Caused by: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)

Fix 1 β€” macOS: run the certificate installer

Fresh Python installs on macOS skip the system keychain entirely. The installer bundles a one-time fix for this.

Open Terminal and run:

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

Swap 3.x for your version β€” for example, 3.12. Using pyenv or Homebrew? Run this instead:

pip install --upgrade certifi

Then verify Python found a valid bundle:

python -c "import ssl; print(ssl.get_default_verify_paths())"

You want a non-empty cafile or capath pointing to an actual file on disk.

Fix 2 β€” install or upgrade certifi

certifi ships a curated CA bundle that requests relies on. If it's outdated β€” or missing β€” verification fails.

pip install --upgrade certifi

Working in a virtualenv? Activate it first, or you'll upgrade the wrong environment:

source venv/bin/activate
pip install --upgrade certifi

Check which bundle Python will actually use:

python -c "import certifi; print(certifi.where())"

Then run a quick sanity test:

import requests
r = requests.get('https://example.com')
print(r.status_code)  # 200 means you're good

Fix 3 β€” add a custom or corporate CA certificate

Behind a corporate firewall? Tools like Zscaler, Charles Proxy, or your company's internal PKI inject their own CA into every HTTPS connection. Python has never heard of that CA β€” hence the error.

Get the CA certificate from your IT team (usually a .crt or .pem file), then pick one of these approaches:

Option A: pass the cert path directly in requests

import requests

r = requests.get('https://internal.company.com', verify='/path/to/company-ca.crt')
print(r.status_code)

Option B: set an environment variable

Works for any library that respects REQUESTS_CA_BUNDLE or SSL_CERT_FILE. Add it to your shell profile so it survives reboots.

# Linux / macOS β€” add to ~/.bashrc or ~/.zshrc
export REQUESTS_CA_BUNDLE=/path/to/company-ca.crt
export SSL_CERT_FILE=/path/to/company-ca.crt
# Windows (PowerShell)
$env:REQUESTS_CA_BUNDLE = "C:\certs\company-ca.crt"

Option C: append the cert to certifi's bundle

Useful when you need a global fix across all scripts in an environment:

import certifi

# Run this once during environment setup
with open('/path/to/company-ca.crt', 'r') as f:
    custom_cert = f.read()

certifi_bundle = certifi.where()
with open(certifi_bundle, 'a') as bundle:
    bundle.write('\n' + custom_cert)

Note: upgrading certifi later will wipe this change. Re-run the script after upgrades.

Fix 4 β€” urllib or http.client (no requests)

Not using requests? The standard library needs a manual SSL context:

import urllib.request
import ssl
import certifi

# Build a context backed by certifi's bundle
ctx = ssl.create_default_context(cafile=certifi.where())

with urllib.request.urlopen('https://example.com', context=ctx) as response:
    print(response.read())

What NOT to do

Stack Overflow is full of answers that suggest disabling verification:

# DO NOT USE IN PRODUCTION
import requests
requests.get('https://example.com', verify=False)  # insecure

# Also bad
import ssl
ssl._create_default_https_context = ssl._create_unverified_context  # insecure

Both approaches silence the error β€” but they do it by turning off the check entirely. Any attacker who intercepts the connection can serve a fake certificate. Python won't complain. Your data leaks.

The only acceptable use is a throwaway test script hitting localhost with no real data. Never against external servers.

Verify the fix worked

Run this snippet to confirm everything is wired up correctly:

python - <<'EOF'
import requests
import ssl
import certifi

print('certifi bundle:', certifi.where())
print('ssl default paths:', ssl.get_default_verify_paths())

r = requests.get('https://httpbin.org/get')
print('HTTP status:', r.status_code)  # expect 200
EOF

Still failing after upgrading certifi? The virtualenv might still be pointing at the old version. Check with:

pip show certifi

The Location field must be inside your active virtualenv β€” not a system Python path like /usr/lib/python3.

Quick decision guide

  • macOS, fresh Python install β†’ Fix 1 (run Install Certificates.command)
  • Any OS, outdated certs β†’ Fix 2 (upgrade certifi)
  • Corporate network / SSL inspection β†’ Fix 3 (add company CA)
  • Not using requests β†’ Fix 4 (urllib with certifi context)

Related Error Notes