How to Fix "Self Signed Certificate in Certificate Chain" in Node.js
Find out which certificate authority your tools reject, then add it to Node.js, npm and git with verification on.
Updated
TL;DR
SELF_SIGNED_CERT_IN_CHAIN means Node.js or npm ended the connection because the chain led up to a root CA it doesn't know, such as your employer's TLS inspection CA. The fastest fix is to get that CA from IT as a PEM file and point NODE_EXTRA_CA_CERTS at it.
What the error looks like in each client
OpenSSL 3 builds write self-signed with a hyphen; OpenSSL 1.1.1 and LibreSSL leave it out. URLs stand in for yours.
| Where | What you see |
|---|---|
| Node.js 20 and 24 https module (code: 'SELF_SIGNED_CERT_IN_CHAIN') | Error: self-signed certificate in certificate chain |
| Node.js 16 (OpenSSL 1.1.1) | Error: self signed certificate in certificate chain |
| Node.js 20 and 24 fetch() | TypeError: fetch failed ... [cause]: Error: self-signed certificate in certificate chain |
| npm 11 | npm error code SELF_SIGNED_CERT_IN_CHAIN |
| npm 8 (Node.js 16) | npm ERR! request to https://registry.npmjs.org/express failed, reason: self signed certificate in certificate chain |
| git 2.41 and 2.50 on macOS | fatal: unable to access 'https://git.example.com/repo.git/': SSL certificate problem: self signed certificate in certificate chain |
| curl 8.7 on macOS (LibreSSL 3.3.6) | curl: (60) SSL certificate problem: self signed certificate in certificate chain |
Why this happens
The chain's top certificate is one your tool was never told to accept.
Inspection proxies on work networks re-sign HTTPS sites with their own root; this code means that root arrived in the chain. Chrome accepts roots IT adds to Windows or macOS, but Node.js checks its bundled Mozilla list by default.
Diagnose your SELF_SIGNED_CERT_IN_CHAIN first
Start in Chrome, then check the error code, the PEM file and which hosts fail.
Open the failing https:// address in Chrome on the same computer; if it loads without a warning, your system already trusts what Node.js lacks.
Read the code in the error; DEPTH_ZERO_SELF_SIGNED_CERT instead means the server's own certificate signed itself, with nothing above it.
Run node -p process.env.NODE_EXTRA_CA_CERTS in the failing terminal; if it prints undefined, Node.js started there without the variable.
Open the file at that path in a text editor; with no -----BEGIN CERTIFICATE----- line, it isn't PEM, and Node.js skips it without warning.
Try a public site and your internal registry or git server; if only internal hosts fail, they use a private company CA, not inspection.
Solutions ranked by effectiveness
Each fix trusts the same root from IT; the first covers every program that runs on Node.js.
- Most common fix
Point NODE_EXTRA_CA_CERTS at IT's root
Applies to Node.js, npm and npx. Take the file only from IT, never from a forum or a warning page; Google warns that installing one yourself is usually a security risk.
Ask IT for the CA as PEM, which Windows calls Base-64 encoded X.509 (.CER).
On macOS or Linux, add export NODE_EXTRA_CA_CERTS="$HOME/certs/company-root.pem" to ~/.zshrc or ~/.bashrc.
On Windows, run setx NODE_EXTRA_CA_CERTS "C:\certs\company-root.pem", then open a new terminal.
- Check next
Let Node.js read the system store
Applies when IT already installed the CA on the computer itself, so Chrome opens those sites. Node.js 22.19, 24.6 and later read certificates the operating system trusts when NODE_USE_SYSTEM_CA=1 is set.
Run node --version; NODE_USE_SYSTEM_CA needs 22.19+ or 24.6+, and older releases ignore it silently.
Set NODE_USE_SYSTEM_CA=1 with export or setx, the same way as NODE_EXTRA_CA_CERTS.
On Node.js 22.15 to 22.18, set NODE_OPTIONS=--use-system-ca; older versions then refuse to start.
- For developers
Trust the root in git per host
Applies when git clone or pull still fails after Node.js works. curl confirms the file matches the server, and the git line scopes trust to that one address; add a line per server.
# company-root.pem: the PEM root from IT; git.example.com: your failing host ROOT="$HOME/certs/company-root.pem" curl --cacert "$ROOT" -sS -o /dev/null -w "%{http_code}\n" https://git.example.com/ git config --global http.https://git.example.com/.sslCAInfo "$ROOT" git ls-remote https://git.example.com/team/repo.git
Stop the SELF_SIGNED_CERT_IN_CHAIN from coming back
Habits that keep one trusted root working across terminals, build machines and root renewals.
Store the PEM at one fixed path, so a new file from IT updates Node.js, npm and git together.
Check its end date with openssl x509 -enddate -noout -in company-root.pem, and ask IT for the successor early.
Compare openssl x509 -noout -fingerprint -sha256 output with the fingerprint IT confirms before trusting any replacement.
Add the file and NODE_EXTRA_CA_CERTS to Dockerfiles and CI jobs that build behind the same network.
Related errors
Learn more
FAQ
A traffic cap for each job
Give each job its own Geonode sticky session with -limit-, which caps that session's bandwidth.


