Error fix · Developer errors

self signed certificate in certificate chain: Causes and Fixes

Fix "self signed certificate in certificate chain" in npm, Node, git and curl: identify the proxy or private CA behind it and trust it safely.

Error messageself signed certificate in certificate chain

By SiteDownCheck Editorial · Updated October 14, 2026 · 4 min read

OpenSSL verification error 19 (X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) means the chain the client received ends in a root certificate that is signed by itself and is not in the client's trust store. Public CAs also have self-signed roots, but clients already trust those. So the message almost always means a private or unknown root is in the path.

You will see it in many forms:

npm ERR! code SELF_SIGNED_CERT_IN_CHAIN
npm ERR! request to https://registry.npmjs.org/express failed, reason: self signed certificate in certificate chain
curl: (60) SSL certificate problem: self-signed certificate in certificate chain
fatal: unable to access '...': SSL certificate problem: self signed certificate in certificate chain

Do not confuse it with error 18, plain self-signed certificate, where the server's own leaf certificate is self-signed. That is usually a dev server. The chain variant points to something re-signing traffic on the way.

Who signed it?

Look at the issuers in the chain the failing machine actually receives:

openssl s_client -connect registry.npmjs.org:443 -servername registry.npmjs.org -showcerts </dev/null 2>/dev/null \
  | grep -E "^ *[0-9] s:|^ *i:|Verify return code"

Compare with a machine on another network, such as a phone hotspot. If the issuer here is your employer, a security vendor or "localhost," the cause is on your path. Common sources:

  1. Corporate TLS inspection proxy. The proxy decrypts HTTPS, then re-signs it with a company root. Employees' browsers trust it because IT installed the root in the operating system store. Command-line tools often use a different store and do not.
  2. Antivirus or endpoint "HTTPS scanning" on a laptop does the same locally.
  3. A private CA used by an internal registry, Git server or API.
  4. A development server using a self-signed or mkcert-style certificate.
  5. A hotel, airport or school network with a captive proxy.

Fix: trust the right root, in the right tool

Get the root certificate as a PEM file from your IT team or export it from the OS store. Then point each tool at it. Each tool has its own setting:

export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corp-root.pem
npm config set cafile /etc/ssl/certs/corp-root.pem

git config --global http.sslCAInfo /etc/ssl/certs/corp-root.pem

curl --cacert /etc/ssl/certs/corp-root.pem https://example.com/

export REQUESTS_CA_BUNDLE=/etc/ssl/certs/corp-bundle.pem
pip config set global.cert /etc/ssl/certs/corp-bundle.pem

sudo cp corp-root.pem /usr/local/share/ca-certificates/corp-root.crt
sudo update-ca-certificates

On RHEL-family systems copy the file to /etc/pki/ca-trust/source/anchors/ and run sudo update-ca-trust. Java keeps its own store; see PKIX path building failed. Docker builds need the root copied into the image too, or the build step that runs npm install fails while your laptop works.

If you run the server and see this from your own client

Your own site presents a self-signed or private-CA certificate that clients do not trust. Choose one:

  • Public service: get a publicly trusted certificate. Free CAs such as Let's Encrypt work; see renewal failures and automation.
  • Internal service: distribute your CA root to every client through configuration management, and issue server certificates from that CA rather than using bare self-signed ones.
  • Local development: use a local CA tool such as mkcert, which installs a development root into your own trust stores.

Also check whether a CDN or load balancer is the party presenting an unexpected certificate; the CDN Detector shows what sits in front.

Confirm the fix

curl -sS -o /dev/null -w "%{http_code} %{ssl_verify_result}\n" https://registry.npmjs.org/

ssl_verify_result of 0 means verification succeeded. Run openssl s_client again for Verify return code: 0 (ok), and for a server you own, check it with the SSL Chain Debugger.

Next steps

FAQ

Why does it work in my browser but not npm?

Your browser uses the operating system store, where IT installed the proxy's root. npm and Node use their own bundled roots, so they must be told about the extra root.

Is a self-signed certificate insecure by itself?

The encryption is fine; the problem is authentication. Clients cannot know the certificate really belongs to your server unless they were given it in advance through a trust store.

Should I disable SSL verification in CI?

No. Add the root certificate to the CI image or runner instead. Disabling checks leaves every dependency download open to tampering.

Why did it begin after I joined a VPN?

Many VPN and secure web gateway products inspect TLS. Check the issuer with openssl before and after connecting.

Get notified when this fix updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.