Python "ssl.SSLCertVerificationError: unable to get local issuer certificate"

Python can't verify the server's chain: missing intermediate on the server, outdated certifi bundle, or a corporate proxy re-signing traffic. Fix the trust source, don't disable verification.

What you'll see

Root causes

Server serves an incomplete chain

Python (unlike browsers) doesn't fetch missing intermediates. If the server sends only the leaf, verification can never complete. openssl s_client -showcerts confirms in one command.

Outdated or absent CA bundle in the environment

requests uses certifi; system Python uses the OS store. Old Docker images / slim bases ship stale bundles. pip install --upgrade certifi, or update-ca-certificates.

Corporate TLS-inspection proxy

The proxy re-signs everything with an internal CA. Without that CA in the bundle, every HTTPS call fails — the corporate-network tell.

Fix it

  1. Check the served chain first (fix the server if incomplete)
    openssl s_client -connect host:443 -servername host -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERT'
  2. Update the bundle Python uses
    pip install --upgrade certifi ; python -c "import certifi; print(certifi.where())"
  3. For corporate CAs: install the internal root properly
    # Debian: cp corp.pem /usr/local/share/ca-certificates/corp.crt && update-ca-certificates ; macOS python: run Install Certificates.command; or REQUESTS_CA_BUNDLE=/path/to/bundle
  4. Scoped trust for scripts (not verification-off)
    # requests.get(url, verify='/path/to/ca-bundle.pem')   # still validates, just against your chosen bundle

Field note

verify=False in code is how outages become breaches: it disables validation everywhere that line runs. Use verify=<ca-bundle> instead. Docker: build with the CA install step, or mount /etc/ssl/certs — slim images are the usual offenders in CI.

Common questions

Why does curl work but Python fails on the same URL?

They read different trust stores (OS bundle vs certifi) and Python won't AIA-fetch missing intermediates. Align the bundle (upgrade certifi / install the private CA) and both behave identically.

What's the right Docker fix?

Install the CA in the image: COPY corp.pem /usr/local/share/ca-certificates/ && RUN update-ca-certificates — or pip install --upgrade certifi if it's just staleness. Never bake verify=False into app code.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.