# npm UNABLE_TO_GET_ISSUER_CERT_LOCALLY: fix npm install

> npm "unable to get local issuer certificate" means Node.js does not trust the root in front of the registry, usually a proxy or private registry. Use cafile.

Source: https://ssl.sh/errors/npm-unable-to-get-local-issuer-certificate/
Last updated: 2026-11-10

**`UNABLE_TO_GET_ISSUER_CERT_LOCALLY` means the HTTPS certificate presented for the npm registry chains to a [root](https://ssl.sh/glossary/root-certificate/) that Node.js does not trust.** On most machines that is a corporate proxy re-signing traffic, or a private registry using an internal CA.

## Quick fix

Adding the company root with `NODE_EXTRA_CA_CERTS` fixes most cases.

Find out who signed the certificate npm sees, here or with the [certificate decoder](https://ssl.sh/tools/certificate-decoder/):

```bash
npm config get registry
openssl s_client -connect registry.npmjs.org:443 -servername registry.npmjs.org </dev/null 2>/dev/null | openssl x509 -noout -issuer
```

If the issuer is your company or a security vendor, get that root (PEM) from IT and add it for every Node.js process:

```bash
export NODE_EXTRA_CA_CERTS=/path/to/company-root.pem
npm install
```

Make it permanent in your shell profile, CI variables or Dockerfile. Alternatively, configure npm only:

```bash
npm config set cafile /path/to/ca-bundle.pem   # must include all roots npm needs
```

Newer npm versions print `npm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY`; the fix is the same.

## Causes

### 1. Corporate proxy or antivirus HTTPS inspection

- **Confirm:** the issuer printed above is not a public CA; the error appears only on the company network or VPN.
- **Fix:** add the proxy root with `NODE_EXTRA_CA_CERTS`. If npm also needs a proxy address, set `npm config set proxy` and `https-proxy` to the URL IT gives you.

### 2. Private registry with an internal CA

Nexus, Artifactory, Verdaccio or GitLab package registries often use certificates from an internal CA.

- **Confirm:** `npm config get registry` shows an internal host; the issuer is your internal CA.
- **Fix:** trust the internal root via `NODE_EXTRA_CA_CERTS`, or scope `cafile` in the project `.npmrc`. If the registry sends an incomplete chain, the error is [unable to verify the first certificate](https://ssl.sh/errors/node-unable-to-verify-leaf-signature/) instead; fix the registry's reverse proxy.

### 3. A `ca` or `cafile` setting that replaced the defaults

- **Confirm:** `npm config list` shows `ca` or `cafile`, possibly from a project, user or global `.npmrc`.
- **Fix:** make that file contain all roots needed (public and private), or remove it and use `NODE_EXTRA_CA_CERTS`.

### 4. Old Node.js or npm

Old releases ship outdated CA lists.

- **Fix:** upgrade to a supported Node.js LTS release, which bundles a current Mozilla CA list.

### 5. A stale or retired mirror

Project or user `.npmrc` files tend to outlive the mirrors they point to. A mirror that moved to a new domain, or an internal mirror whose certificate was replaced by an internally signed one, produces this error or a related one such as [CERT_HAS_EXPIRED](https://ssl.sh/errors/node-cert-has-expired/).

- **Confirm:** `npm config get registry` and `npm config list` show a host you did not expect; `npm ping` fails for it.
- **Fix:** point the registry at the current URL with `npm config set registry <url>`, or delete the stale line from the `.npmrc` that sets it.

## Fixes by environment

Every environment uses the same fix: point `NODE_EXTRA_CA_CERTS` or npm's `cafile` at a PEM file with the missing root. Node.js code outside npm fails the same way, see [UNABLE_TO_GET_ISSUER_CERT_LOCALLY in Node.js](https://ssl.sh/errors/node-unable-to-get-issuer-cert-locally/).

**Windows:** `setx NODE_EXTRA_CA_CERTS C:\certs\company-root.pem`, then open a new terminal. Export the root from the Windows store in Base-64 (PEM) format first.

**macOS / Linux:** add `export NODE_EXTRA_CA_CERTS=...` to `~/.zshrc` or `~/.bashrc`.

**Docker:**

```dockerfile
COPY company-root.pem /usr/local/share/ca-certificates/company-root.crt
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/company-root.crt
RUN npm ci
```

**CI (GitHub Actions, GitLab CI, Jenkins):** store the PEM as a file secret and export `NODE_EXTRA_CA_CERTS` before `npm ci`.

**Packages with postinstall downloads** (for example browser or native binaries fetched during install) use their own HTTPS requests, so only `NODE_EXTRA_CA_CERTS` covers them, not npm's `cafile`.

## Don't do this

- **`npm config set strict-ssl false`.** npm will accept any certificate for the registry, so a man-in-the-middle can serve modified packages that run code on your machine through install scripts.
- **`NODE_TLS_REJECT_UNAUTHORIZED=0 npm install`.** Same risk, for every connection made during install.
- **Switching the registry to `http://`.** Removes encryption and integrity in transit entirely.
