How to fix npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT in npm
The DEPTH_ZERO_SELF_SIGNED_CERT error occurs when npm reaches a self-signed certificate at the root of the chain (depth zero). Fix it by trusting that certificate via npm's cafile or your OS trust store.
Quick fix
Fixes npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT
openssl s_client -connect your-registry:443 </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subject- Verify it is actually a self-signed certificate
- Export the self-signed certificate
- Tell npm to trust the certificate (recommended)
- Or add it to the system trust store
openssl s_client -connect your-registry:443 </dev/null 2>/dev/null \| openssl x509 -noout -issuer -subjectnpm ERR! DEPTH_ZERO_SELF_SIGNED_CERT
What this error means
This error indicates that the very first certificate npm encountered (at "depth zero" in the certificate chain) is self-signed. Unlike SELF_SIGNED_CERT_IN_CHAIN, where a self-signed certificate appears somewhere along an otherwise normal chain, this error means there is effectively no chain of trust at all - just a single self-signed certificate presented by the server. It commonly occurs when talking to development servers, local registries, or proxies that present certificates generated with tools like openssl or mkcert without those certificates having been added to a trusted CA store. Node.js/npm validates the certificate against the system (or configured) trust anchors, finds no matching trusted root, and aborts the TLS handshake.
Typical symptoms
- npm install fails with DEPTH_ZERO_SELF_SIGNED_CERT
- Error appears when accessing a local or private npm registry
- A working development environment suddenly stops installing packages
- Problem starts after a network or proxy change
- Other HTTPS tools (curl, git) against the same host also fail TLS verification
- Error is specific to one registry or host URL
Common causes
- Private registry serving a self-signed certificate
- Local npm server (Verdaccio, etc.) using its default self-signed certificate
- Development proxy presenting a self-signed certificate
- Corporate proxy intercepting TLS with a certificate not in your trust store
- mkcert- or openssl-generated certificate that was never added to a trust store
- Misconfigured reverse proxy presenting only a leaf self-signed certificate
- Testing/CI environment configured with an untrusted certificate
How to fix "npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT"
Inspect the certificate the registry presents:
openssl s_client -connect your-registry:443 </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -subjectIf the issuer equals the subject, the certificate is self-signed (depth zero), which confirms this error.
Save the certificate so you can add it to a trust store:
openssl s_client -connect your-registry:443 </dev/null 2>/dev/null \
| openssl x509 > self-signed.crtIf the registry is reachable in a browser, you can also export the certificate from the browser's certificate viewer as a PEM (.crt/.pem) file.
Point npm at a CA file containing the certificate. cafile is a global npm setting - npm does not support a per-registry cafile key, so configure it once:
npm config set cafile /path/to/self-signed.crtcafile should contain the trust anchor: for a true self-signed leaf, that is the certificate itself; if the server is fronted by a private CA, use that CA's certificate. To combine your private CA with the public roots Node ships, set the environment variable instead so the default roots are kept:
export NODE_EXTRA_CA_CERTS=/path/to/self-signed.crtThis is the safest fix because TLS verification stays enabled - you are only adding a new trust anchor, not disabling checks.
Trusting the certificate at the OS level fixes npm and every other TLS client (git, curl, etc.) at once:
# Ubuntu/Debian
sudo cp self-signed.crt /usr/local/share/ca-certificates/your-registry.crt
sudo update-ca-certificates
# RHEL/Fedora
sudo cp self-signed.crt /etc/pki/ca-trust/source/anchors/your-registry.crt
sudo update-ca-trust
# macOS
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain self-signed.crt
# Windows (run PowerShell/cmd as admin)
certutil -addstore -f "ROOT" self-signed.crtOn Linux, set NODE_EXTRA_CA_CERTS (see step 3) or npm config set cafile as well, because Node does not automatically read the system store.
mkcert installs a local CA into your system (and browser) trust stores, so certificates it issues are trusted automatically - avoiding self-signed errors entirely:
# Install mkcert (examples)
brew install mkcert # macOS
# choco install mkcert # Windows
# apt install mkcert # Debian/Ubuntu (or download the release binary)
# Install the local CA into the trust stores
mkcert -install
# Generate a certificate for your local registry host
mkcert localhost 127.0.0.1 ::1Serve your local registry with the generated *.pem files and npm will trust them with no further configuration.
Prefer the trust-based fixes above. Only if you cannot obtain or install the certificate (for example, a throwaway local test) should you temporarily turn off verification. This disables TLS certificate checks entirely and exposes you to man-in-the-middle attacks, so never do this for production, shared, or CI machines, and re-enable it immediately afterward.
# Per-command (preferred - scoped, not persisted)
npm install --strict-ssl=false
# Or globally (remember to undo it)
npm config set strict-ssl false
# ...then re-enable:
npm config set strict-ssl trueAdvanced notes
For production private registries, use certificates issued by a real CA (Let's Encrypt is free and automatable) rather than self-signed certificates, so no client-side trust configuration is needed. In Kubernetes, manage certificates with cert-manager. For local development, mkcert creates locally-trusted certificates that work across tools without per-client setup.
Note the distinction between npm's trust settings: cafile/ca and strict-ssl are global npm config keys, not per-registry keys - only authentication settings (such as //registry:port/:_authToken or :username) are scoped per registry. To make Node itself trust a private CA without replacing its built-in roots, prefer the NODE_EXTRA_CA_CERTS environment variable, which is additive. When distributing to a team, ship the CA via configuration management or document the OS trust-store install steps so every machine trusts it consistently.
Frequently asked questions
- What does "npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT" mean?
- This error indicates that the very first certificate npm encountered (at "depth zero" in the certificate chain) is self-signed. Unlike SELF_SIGNED_CERT_IN_CHAIN, where a self-signed certificate appears somewhere along an otherwise normal chain, this error means there is effectively no chain of trust at all - just a single self-signed certificate presented by the server. It commonly occurs when talking to development servers, local registries, or proxies that present certificates generated with tools like openssl or mkcert without those certificates having been added to a trusted CA store.
- How do I fix "npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT"?
- The DEPTH_ZERO_SELF_SIGNED_CERT error occurs when npm reaches a self-signed certificate at the root of the chain (depth zero). Fix it by trusting that certificate via npm's cafile or your OS trust store.
- What causes "npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT"?
- Private registry serving a self-signed certificate Local npm server (Verdaccio, etc.) using its default self-signed certificate Development proxy presenting a self-signed certificate
- Is the "npm ERR! DEPTH_ZERO_SELF_SIGNED_CERT" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐npm Official Documentation
- ๐
- ๐