Certificates2026-05-30

'Fix "unable to get local issuer certificate"'

'The "unable to get local issuer certificate" error means a missing intermediate or untrusted root. Here is what causes it and how to fix it in curl, Node, Python, Git, and Java.'

ssltlscertificateerrortroubleshootingcurl

Fix "unable to get local issuer certificate"

You ran a curl, an npm install, a git clone, or a Python requests call and got:

SSL certificate problem: unable to get local issuer certificate

It's one of the most common TLS errors, and it almost never means the server is broken. It means your client couldn't build a complete trust chain from the server's certificate up to a root CA it trusts. This guide explains why, then fixes it for each major tool.

What the Error Actually Means

When a server presents its certificate during the TLS handshake, your client has to verify it chains up to a trusted root certificate authority. That chain looks like:

Leaf (your-server.com)
  └─ signed by → Intermediate CA
       └─ signed by → Root CA (in your trust store)

"Unable to get local issuer certificate" means the client can't find the issuer of some link in that chain. Two root causes account for nearly all cases:

1. The server didn't send its intermediate certificate. The most common cause. The server presents only its leaf certificate, but the client needs the intermediate to bridge to the root. Browsers often paper over this by caching intermediates; curl and other CLI tools don't, so they fail where the browser succeeds.

2. The root CA isn't in your trust store. Your system's CA bundle is outdated, or the cert chains to a private/corporate CA you haven't installed.

Step 1 — Diagnose the Chain

Before changing anything, find out which link is missing. Inspect what the server is actually sending:

openssl s_client -connect example.com:443 -showcerts

Look at the certificates returned. If you only see one (the leaf) and no intermediate, that's cause #1. The SSL Checker does the same diagnosis in the browser — point it at the domain and it reports whether the chain is complete. To inspect a specific certificate file, drop it into the Certificate Decoder or SSL Decoder to see its issuer and confirm which CA should be next in the chain.

Step 2 — Fix It Per Tool

curl

If the server is missing its intermediate, the real fix is server-side (below). To make curl work against a server with a private/corporate CA, point it at the CA bundle:

curl --cacert /path/to/ca-bundle.pem https://example.com

Or update your system bundle. Do not use curl -k / --insecure outside of throwaway testing — it disables verification entirely and defeats the purpose of TLS.

Node.js

Node ships its own CA store and is strict about chains. For a corporate/private CA, point Node at the extra CA:

export NODE_EXTRA_CA_CERTS=/path/to/ca.pem
node app.js

Never set NODE_TLS_REJECT_UNAUTHORIZED=0 in production — it turns off all certificate validation process-wide.

Python (requests / pip)

# requests: point at a CA bundle
python -c "import requests; requests.get('https://example.com', verify='/path/to/ca.pem')"

# pip behind a corporate proxy/CA
pip install --cert /path/to/ca.pem <package>

The certifi package provides Python's bundle; upgrading it (pip install -U certifi) fixes cases where the root is simply outdated.

Git

# Point Git at the right CA bundle
git config --global http.sslCAInfo /path/to/ca-bundle.pem

Again, avoid git config --global http.sslVerify false — it's the -k of Git.

Java

Java uses its own keystore (cacerts), not the OS store. Import the missing root/intermediate:

keytool -import -trustcacerts -alias mycorp \
  -file intermediate.pem \
  -keystore $JAVA_HOME/lib/security/cacerts

Step 3 — The Real Fix (Server-Side)

If the cause is a missing intermediate (cause #1), the correct fix is on the server, not every client. Configure the server to send the full chain — leaf + intermediate(s) — concatenated in the right order:

-----BEGIN CERTIFICATE-----   ← your leaf certificate
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----   ← intermediate CA certificate
...
-----END CERTIFICATE-----

Your CA provides the intermediate ("CA bundle" or "chain file"). In Nginx, point ssl_certificate at this combined fullchain.pem. In Apache, set SSLCertificateChainFile (or include the chain in SSLCertificateFile on modern versions). To confirm you assembled the file in the right order, paste it into the PEM Decoder — it'll show each certificate block and its issuer so you can verify leaf → intermediate → root.

Once the server sends the full chain, every client — curl, Node, Java, and browsers — verifies it without per-client workarounds.

Why the Browser Worked but curl Didn't

A frequent source of confusion: the site loads fine in Chrome but fails in curl or your CI pipeline. That's because browsers cache and auto-fetch intermediate certificates (via the AIA extension), masking a missing-intermediate misconfiguration. CLI tools and language runtimes generally don't. So "works in my browser" doesn't mean the chain is complete — always test with openssl s_client or the SSL Checker.

Quick Reference

  • The error = your client can't build a trust chain: usually a missing intermediate or an untrusted root.
  • Diagnose with openssl s_client -showcerts or the SSL Checker; inspect certs with the Certificate Decoder.
  • Per-client fix: point the tool at the correct CA bundle (--cacert, NODE_EXTRA_CA_CERTS, certifi, http.sslCAInfo, keytool).
  • The real fix for a missing intermediate is server-side: serve the full chain (leaf + intermediate). Verify order with the PEM Decoder.
  • Never disable verification (-k, sslVerify false, NODE_TLS_REJECT_UNAUTHORIZED=0) outside throwaway testing.