What it means: The chain ends in a root certificate that your client's trust store does not contain.
Free online tool — SSL certificate checker: instant results, no signup.
Runs a full TLS check: handshake, protocol versions, certificate chain, trust and expiry.
It is OpenSSL verification error 19, X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: «The certificate chain could be built up using the untrusted certificates but no suitable trust anchor (which typically is a self-signed root certificate) could be found in the trust store» (X509_STORE_CTX_get_error). The server sent a complete chain all the way up to a self-signed root, and that root is not one the client trusts.
The spelling depends on the OpenSSL version: OpenSSL 3 prints self-signed certificate in certificate chain, OpenSSL 1.1.1 printed self signed certificate in certificate chain (x509_txt.c). You will see it as:
code SELF_SIGNED_CERT_IN_CHAIN, message self-signed certificate in certificate chain.curl: (60) SSL certificate problem: self-signed certificate in certificate chain.certificate verify failed: self-signed certificate in certificate chain; see the Python page for its trust store specifics.Its neighbour is error 18, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (DEPTH_ZERO_SELF_SIGNED_CERT in Node.js): there the server's own certificate is self-signed, with no chain at all. OpenSSL picks 18 when the self-signed certificate is the only one, and 19 when it sits at the top of a longer chain (x509_vfy.c).
| Root at the top of the chain | What is going on | Right fix |
|---|---|---|
| Your company, a firewall vendor or an antivirus product | TLS inspection: a proxy decrypts traffic and re-signs it with its own CA | Install that CA in each tool's trust store |
| An internal CA (Kubernetes, Vault, an internal PKI) | A private service with a private root | Distribute the root to the clients that call it |
| A public CA root that your client lacks | Outdated trust store, old OS or container image | Update ca-certificates or the runtime |
| A root you have never heard of on a public site | Possible interception on the network | Stop and investigate before trusting anything |
TLS inspection is the most common case on work laptops. The browser trusts the proxy's root because IT installed it in the operating system, but Node.js ships its own list of roots and many Python installs use certifi, so command-line tools still fail. Whether you see error 19 or error 20 depends on the proxy: if it sends its root inside the chain you get 19; if it sends only the re-signed leaf and an intermediate, you get unable to get local issuer certificate.
openssl s_client -connect registry.npmjs.org:443 -servername registry.npmjs.org -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9] s:|^ *i:'The last certificate whose subject (s:) equals its issuer (i:) is the self-signed root. Run the same command from a network without inspection (a phone hotspot): if the issuer changes, a proxy is re-signing traffic. Before you add any root to a trust store, save it and compare its fingerprint with the one your IT or PKI team publishes:
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
| awk '/BEGIN CERT/{n++; p=1} p{print > ("chain-" n ".pem")} /END CERT/{p=0}'
ls chain-*.pem
openssl x509 -in chain-3.pem -noout -subject -fingerprint -sha256 # the last file is the top of the chainTrusting a root means trusting everything it signs, for every host. Do it only for a root you can attribute to someone responsible for it.
cp corp-root.pem /usr/local/share/ca-certificates/corp-root.crt && update-ca-certificates. curl, Git and most system OpenSSL users pick it up.export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root.crt before starting the process; the variable is read only at launch (Node.js CLI). On Node 23.8+, --use-system-ca makes Node trust the OS store where IT already installed the root.npm config set cafile /usr/local/share/ca-certificates/corp-root.crt. Leave strict-ssl at its default true.pip install --cert /path/corp-bundle.pem ... or set the cert option in pip's config; the bundle must contain the corporate root.npm config set strict-ssl false, NODE_TLS_REJECT_UNAUTHORIZED=0 and curl -k. They hide this error by accepting any certificate, including an attacker's.curl -sS -o /dev/null -w '%{http_code}\n' https://registry.npmjs.org/
# 200
node -e "fetch('https://registry.npmjs.org/').then(r => console.log(r.status), e => console.log(e.cause?.code))"
# 200
npm pingIf you run the server, check what the public sees: the SSL/TLS checker builds the chain from outside your network, without any corporate root, and shows whether it ends at a publicly trusted CA.
SSL/TLS is the encryption protocol that protects data between the browser and server. Our tool analyzes the certificate, chain of trust, TLS version, and knownvulnerabilities.
Issuer, validity period, signature algorithm, covered domains (SAN), and validation type (DV/OV/EV).
Full chain verification: from leaf certificate through intermediates to root CA.
Protocol version (TLS 1.2/1.3), cipher suites, Perfect Forward Secrecy (PFS) support.
Set up a monitor — get Telegram and email alerts 30/14/7 days before expiration.
SSL certificate monitoring
TLS config audit
HTTPS as ranking factor
customer trust
www and subdomains.Strict-Transport-Security header forces browsers to always use HTTPS.SSL certificate monitoring, check history and alerts 30 days before expiry.
Sign up freeYour work network inspects TLS and re-signs traffic with a corporate root. The browser trusts it through the OS, but npm and Node.js use their own root list; add the corporate root with npm config set cafile or NODE_EXTRA_CA_CERTS.
No. It makes npm accept any certificate for the registry, so a tampered package could be served without a warning. Trust the specific root instead.
DEPTH_ZERO_SELF_SIGNED_CERT means the server certificate itself is self-signed. SELF_SIGNED_CERT_IN_CHAIN means a longer chain ends in a self-signed root that you do not trust.
It is not needed: clients use the root from their own trust store. Sending it does no harm, but it does not make an untrusted root trusted.
OpenSSL 3 prints self-signed with a hyphen, OpenSSL 1.1.1 printed self signed without one. Both are error 19.
Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.