What This Error Means
npm received a self-signed certificate from the registry or proxy.
How to Fix It
- Confirm which registry host npm is calling:
npm config get registry. - Check for proxy settings:
npm config get proxyandnpm config get https-proxy. - Check TLS config:
npm config get strict-sslandnpm config get cafile. - Run a quick registry check:
npm ping. - If this only fails on your office/VPN but works on a hotspot, treat it as corporate TLS interception until proven otherwise.
- Quick confirmation (insecure, temporary): run once with
npm --strict-ssl=false <command>. If it works, fix CA trust instead of leaving SSL checks disabled. - Alternative temporary config toggle (insecure):
npm config set strict-ssl false, retry once, then immediately revert:npm config set strict-ssl true. - Alternative one-off (insecure): run once with
NODE_TLS_REJECT_UNAUTHORIZED=0(do not use in CI, remove afterward). - Proper fix: trust the CA that is signing the certificate chain.
- If you are behind a corporate TLS proxy, export the corporate root CA and configure npm:
npm config set cafile /path/to/corp-ca.pem. - In CI, prefer
NODE_EXTRA_CA_CERTS=/path/to/corp-ca.pemso Node trusts the internal CA without changing global npm config. - If you control the registry/proxy, ensure it serves the full certificate chain (leaf + intermediates).
- Inspect the served chain:
openssl s_client -showcerts -connect <host>:443 -servername <host> </dev/null. - Retry with
npm --verboseand keep the full output for troubleshooting.
Why It Happens
- A corporate proxy/VPN is intercepting HTTPS and presenting a certificate signed by an internal CA that Node does not trust.
- Your registry (or proxy registry) is serving an incomplete chain (missing intermediate CA certificates).
- System time is incorrect, which can make otherwise valid certificates fail validation.
- Node/npm is using a CA trust store that does not include the required issuer certificates.
How to Verify
- Run
npm ping(same network, same registry) and confirm it succeeds. - Re-run the original command and confirm the TLS error no longer appears.
Manual certificate validation
- Confirm the failing host matches your registry:
npm config get registry. - If you control the registry/proxy, ensure it serves the full certificate chain (leaf + intermediates).
- Inspect the served chain:
openssl s_client -showcerts -connect <host>:443 -servername <host> </dev/null. - If
curlworks but npm fails, the issue is usually Node's CA trust (fix withNODE_EXTRA_CA_CERTS/cafile). - If you need a quick confirmation, disable strict SSL for one retry only, then revert it.
Common CLI Output
npm ERR! code DEPTH_ZERO_SELF_SIGNED_CERT How npm verifies TLS certificates
- npm uses Node.js for HTTPS. Certificate validation happens in Node's TLS stack.
- The server must provide a valid chain to a trusted root CA, and the certificate must match the hostname.
- Proxies that intercept TLS must be trusted by adding their root CA to the client trust store (or configuring
cafile).
Prevention Tips
- Bake your corporate root CA into CI runner images (or distribute via configuration management).
- Use a registry/proxy that serves a complete, valid certificate chain.
- Keep Node.js and npm updated so you get current CA bundles and TLS defaults.
Where This Can Be Triggered
github.com/npm/cli/blob/417daa72b09c5129e7390cd12743ef31bf3ddb83/lib/utils/ping.js
This is the registry request path where npm talks to the network. DNS/TLS errors like this code are raised by Node/OS during this request. - GitHub
// used by the ping and doctor commands
const npmFetch = require('npm-registry-fetch')
module.exports = async (flatOptions) => {
const res = await npmFetch('/-/ping', { ...flatOptions, cache: false })
return res.json().catch(() => ({}))
}