unable to get local issuer certificate

The program found no authority it trusts to vouch for the server’s certificate. The fix is in that program’s own list, and each program keeps a different one.

curlcurl: (60) SSL certificate problem: unable to get local issuer certificate
gitfatal: unable to access 'https://...': SSL certificate problem: unable to get local issuer certificate
Python, pip[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate
Node.jsError: unable to get local issuer certificate (UNABLE_TO_GET_ISSUER_CERT_LOCALLY)

What it means

The program received the server’s certificate and looked for the certificate of whoever issued it - first among what the server sent, then in its local trust store. It found neither. “Local” means this program’s own list of authorities, which is not necessarily the one your browser uses.

The message comes from OpenSSL and the libraries built like it, which is why curl, git, Python, pip and Node.js all print it.

Common causes

  • A company root missing from this program’s list. A TLS inspection proxy or your company’s own authority signs the connection, and IT added its root to the system store. curl on Windows may trust it, while Git for Windows, Python and Node.js read lists of their own that do not have it.
  • The server does not send its intermediate certificate. A browser hides this by remembering the intermediate from another site. Every other client fails. Missing intermediate certificate covers it.
  • An outdated or replaced CA bundle. A program pointed at another file, through SSL_CERT_FILE, CURL_CA_BUNDLE, REQUESTS_CA_BUNDLE or GIT_SSL_CAINFO, trusts that file and nothing else.

Find which one is yours

certdoctor https://the-url-that-fails/

L0 shows which of those variables are set. L4 shows whether the server sent its whole chain. The trust matrix shows every git, curl, Python, pip and node on the machine, which list each one reads, which of them refuse, and the command that adds the root to each.

If the verdict says the server did not send the issuer of its certificate, the fix belongs on the server, and certdoctor says so: “this is a fact about the server rather than about this machine.”

Fix it

Add the root to the list the failing program reads, with the command its row prints:

If the root is your company’s, TLS inspection says how to get the right certificate.

What not to do

git config http.sslVerify false, curl -k, verify=False and NODE_TLS_REJECT_UNAUTHORIZED=0 make the error go away by accepting any certificate from anyone. They hide the problem rather than fix it, and they stay set long after everybody has forgotten why.