# Node.js / npm: “self-signed certificate in certificate chain”

> SELF_SIGNED_CERT_IN_CHAIN or unable to get local issuer certificate in Node.js or npm. Trust your company CA with NODE_EXTRA_CA_CERTS, not by disabling TLS.

Canonical: https://app369.com/fix/node-self-signed-certificate-in-chain/
Last updated: 2026-11-08

npm install, a fetch() call or an SDK fails with self-signed certificate in certificate chain (code SELF_SIGNED_CERT_IN_CHAIN), unable to get local issuer certificate, or DEPTH_ZERO_SELF_SIGNED_CERT. Node.js could not trace the server’s certificate to a certificate authority it trusts. On work laptops this is almost always a company proxy or security tool that re-signs HTTPS traffic with its own root certificate. Against a public server, unable to get local issuer certificate can also mean the server does not send its intermediate certificate, which only the server owner can fix.

**Short answer**

Get your company’s root certificate as a PEM file from IT, then point Node.js at it with NODE_EXTRA_CA_CERTS=/path/company-ca.pem (npm runs on Node.js, so this covers npm install too). It is read when the process starts, so set it in the shell or CI environment, not inside your script. On Node.js 22.15 or newer, --use-system-ca makes Node.js trust the certificates your operating system already trusts. For your own local HTTPS server, use a locally trusted CA (for example with mkcert) instead of a raw self-signed certificate. Do not set NODE_TLS_REJECT_UNAUTHORIZED=0 or strict-ssl=false.

## **Why the certificate is not trusted, and the fix**

1. 01 ### **A company proxy or security tool re-signs traffic**
  > “When set, the well known "root" CAs (like VeriSign) will be extended with the extra certificates in file.” [**Node.js, Command-line options: NODE_EXTRA_CA_CERTS**](https://nodejs.org/api/cli.html) Tools such as Zscaler, Netskope or antivirus HTTPS scanning replace each site’s certificate with one signed by the company’s own root. The operating system trusts that root; Node.js uses its own bundled list and does not. Add the root to Node.js.```
# macOS / Linux, in ~/.zshrc or ~/.bashrc
export NODE_EXTRA_CA_CERTS="$HOME/certs/company-ca.pem"
```
2. 02 ### **npm install fails the same way**
  > “A path to a file containing one or multiple Certificate Authority signing certificates.” [**npm Docs, npm config: cafile**](https://docs.npmjs.com/cli/v11/using-npm/config) NODE_EXTRA_CA_CERTS already covers npm, because npm runs on Node.js. Use npm’s cafile setting only if you must: it replaces npm’s default certificate list instead of adding to it, so the file has to contain the full chain npm needs.```
npm config set cafile "$HOME/certs/company-ca.pem"
```
3. 03 ### **Turning verification off**
  > “This makes TLS, and HTTPS by extension, insecure. The use of this environment variable is strongly discouraged.” [**Node.js, Command-line options: NODE_TLS_REJECT_UNAUTHORIZED**](https://nodejs.org/api/cli.html) NODE_TLS_REJECT_UNAUTHORIZED=0 and npm strict-ssl=false make the error go away by accepting any certificate, including an attacker’s. Never ship them, and remove them from shell profiles and CI once the real CA is in place.
4. 04 ### **Your own self-signed development certificate** A local API on https://localhost with a self-signed certificate fails the same check. Create the certificate with a local CA that your machine trusts (mkcert does this), then add that CA to NODE_EXTRA_CA_CERTS for Node.js clients. This is for development only; never share the rootCA-key.pem file mkcert creates.```
mkcert -install
mkcert localhost
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
```

Checked against the vendor’s docs on November 8, 2026: [Node.js: Command-line options (NODE_EXTRA_CA_CERTS, --use-system-ca)](https://nodejs.org/api/cli.html); [npm Docs: config (cafile)](https://docs.npmjs.com/cli/v11/using-npm/config).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**npm “EACCES: permission denied”**](https://app369.com/fix/npm-eacces-permission-denied/) · [**Node.js ERR_OSSL_EVP_UNSUPPORTED**](https://app369.com/fix/node-err-ossl-evp-unsupported/) · [**Node.js “getaddrinfo ENOTFOUND”**](https://app369.com/fix/node-getaddrinfo-enotfound/) · [**Node.js “certificate has expired”**](https://app369.com/fix/node-certificate-has-expired/)

Questions

## **More on this error**

<details>

<summary>**Where do I get the company certificate? **+</summary>

Ask IT for the root CA used by the proxy, in PEM format. You can also export it from your operating system’s certificate store (Keychain Access on macOS), where it is already trusted.

</details>

<details>

<summary>**Why does the browser work but Node.js fails? **+</summary>

Browsers use the operating system’s trusted certificates, which include the company root. Node.js uses its own bundled list unless you add the root or enable the system store.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)