Geonode logo
Secure connection errors

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.

WhereWhat 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 11npm 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 macOSfatal: 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.

  1. 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.

    1. Ask IT for the CA as PEM, which Windows calls Base-64 encoded X.509 (.CER).

    2. On macOS or Linux, add export NODE_EXTRA_CA_CERTS="$HOME/certs/company-root.pem" to ~/.zshrc or ~/.bashrc.

    3. On Windows, run setx NODE_EXTRA_CA_CERTS "C:\certs\company-root.pem", then open a new terminal.

  2. 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.

    1. Run node --version; NODE_USE_SYSTEM_CA needs 22.19+ or 24.6+, and older releases ignore it silently.

    2. Set NODE_USE_SYSTEM_CA=1 with export or setx, the same way as NODE_EXTRA_CA_CERTS.

    3. On Node.js 22.15 to 22.18, set NODE_OPTIONS=--use-system-ca; older versions then refuse to start.

  3. 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.

  1. Store the PEM at one fixed path, so a new file from IT updates Node.js, npm and git together.

  2. Check its end date with openssl x509 -enddate -noout -in company-root.pem, and ask IT for the successor early.

  3. Compare openssl x509 -noout -fingerprint -sha256 output with the fingerprint IT confirms before trusting any replacement.

  4. Add the file and NODE_EXTRA_CA_CERTS to Dockerfiles and CI jobs that build behind the same network.

Proxy logins in environment variablesGeonode's Puppeteer guide loads host, port, username and password from process.env, not source files.
Try residential proxies

Related errors

Learn more

FAQ

It means the CA at the top of the chain is missing from your client's trust store. Roots vouch for themselves, so the wording flags an unknown authority, not a damaged certificate.

Point NODE_EXTRA_CA_CERTS at IT's root and rerun npm install; npm reads it at startup like any Node.js program. Keep strict-ssl on: turning it off stops npm checking the registry's certificate, and npm's docs advise a CA file instead.

git verifies through libcurl, not Node.js, so NODE_EXTRA_CA_CERTS never reaches it. On Git for Windows, git config --global http.sslBackend schannel switches to the Windows certificate store, which holds roots IT distributes through Active Directory.

Behind HTTPS inspection, the message means the device sent its issuing CA but not the root that signed it. When the root comes along, Node.js reports SELF_SIGNED_CERT_IN_CHAIN instead, and IT's PEM file fixes both.

No. Node.js 24 appends that hint to a few certificate errors, such as DEPTH_ZERO_SELF_SIGNED_CERT, but not to this one, so a missing hint doesn't mean the system store can't help.

A library that passes its own ca option makes Node.js skip both its bundled roots and NODE_EXTRA_CA_CERTS for that client. Add IT's root to that library's CA setting.

A traffic cap for each job

Give each job its own Geonode sticky session with -limit-, which caps that session's bandwidth.