Node.js "self signed certificate in certificate chain" - Fix TLS in CI
By Daniel Zoghalchali·Latchkey
Node could not validate the TLS chain because it ends in a self-signed certificate it does not trust - almost always a corporate proxy re-signing HTTPS. The fix is to trust the proxy’s CA, not to switch verification off.
What this error means
npm install, a fetch, or any HTTPS call fails with self signed certificate in certificate chain (code SELF_SIGNED_CERT_IN_CHAIN). It is environment-specific - it passes on an unproxied machine and fails behind the corporate proxy.
npm / Node output
npm error code SELF_SIGNED_CERT_IN_CHAIN
npm error errno SELF_SIGNED_CERT_IN_CHAIN
npm error request to https://registry.npmjs.org/... failed,
reason: self signed certificate in certificate chain
Diagnose it: which registry, and with what credentials?
Registry errors are resolved in a precedence chain, and the effective value is rarely the one in the file you are looking at. Scoped registries, .npmrc files at several levels, and environment variables all combine before a request is made.
Terminal
# the effective, fully merged configuration
npm config list -l | grep -E "registry|_auth|always-auth"
# where each value came from
npm config get registry
npm config get @yourscope:registry
# prove the token works, independently of the install
curl -sI -H "Authorization: Bearer $NPM_TOKEN" \
"$(npm config get registry)@yourscope%2fpackage" | head -1
Common causes
A TLS-intercepting proxy
A corporate proxy terminates TLS and re-signs traffic with its own root CA. Node does not trust that CA, so the chain validation fails with a self-signed-certificate error.
Missing CA bundle on a minimal image
A slim runner image without an up-to-date CA store cannot validate otherwise-legitimate chains.
How to fix it
Trust the proxy’s CA (correct fix)
Point Node and npm at the extra CA file instead of disabling verification.
Terminal
# Node: add the corporate root CA
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corporate-root.pem
# npm: point at the same CA bundle
npm config set cafile /etc/ssl/certs/corporate-root.pem
npm ci
Never disable verification permanently
Setting NODE_TLS_REJECT_UNAUTHORIZED=0 makes Node accept any certificate - it turns off the protection that catches real interception. Use it only to confirm the diagnosis, never as the fix.
Terminal
# diagnosis ONLY - do not leave this set
NODE_TLS_REJECT_UNAUTHORIZED=0 node -e "require('https').get('https://registry.npmjs.org', r=>console.log(r.statusCode))"
How to prevent it
Install the proxy’s root CA into the runner image and use NODE_EXTRA_CA_CERTS.
Keep ca-certificates current on runner images.
Never leave NODE_TLS_REJECT_UNAUTHORIZED=0 set in CI.
Frequently asked questions
What causes Node.js "self signed certificate in certificate chain"?
There are 2 common causes: a tls-intercepting proxy and missing ca bundle on a minimal image. A corporate proxy terminates TLS and re-signs traffic with its own root CA.
How do I fix Node.js "self signed certificate in certificate chain"?
There are 2 fixes depending on which cause you have: trust the proxy’s ca (correct fix) and never disable verification permanently. Work through them in order, since the first is the most common.
What does Node.js "self signed certificate in certificate chain" actually mean?
npm install, a fetch, or any HTTPS call fails with self signed certificate in certificate chain (code SELF_SIGNED_CERT_IN_CHAIN).
How do I stop Node.js "self signed certificate in certificate chain" happening again?
Install the proxy’s root CA into the runner image and use NODE_EXTRA_CA_CERTS. The prevention section lists 3 changes that keep it from recurring.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.
This is a transient network failure, not a bug in your code. Latchkey detects, repairs, and retries it for you.Start free →30-day trial · No credit card
Cookie Preferences
Choose which categories of cookies you want to allow. Essential cookies are always active as they are required for the site to function.
Essential
Required for the site to function.
Functional
Remembers your preferences like selected organization and dashboard settings.
Analytics
Helps us understand how the site is used (Google Analytics).