Command-line tools

npm UNABLE_TO_GET_ISSUER_CERT_LOCALLY: fix npm install

By · Last verified

Error messagenpm ERR! code UNABLE_TO_GET_ISSUER_CERT_LOCALLY

UNABLE_TO_GET_ISSUER_CERT_LOCALLY means the HTTPS certificate presented for the npm registry chains to a root 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:

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:

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:

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

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

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:

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.

FAQ

Should I use cafile or NODE_EXTRA_CA_CERTS?

cafile is read by npm itself and, like the ca setting, replaces npm's default CA list for registry requests, so the file must contain every root you need. NODE_EXTRA_CA_CERTS adds certificates to Node's defaults for every Node.js process, which also fixes postinstall scripts that download binaries. Behind a corporate proxy, NODE_EXTRA_CA_CERTS is usually the less surprising choice.

Why does the error appear only on the office network?

Your company proxy is decrypting HTTPS and re-signing it with its own root. At home you connect to the registry directly and see its public certificate. Ask IT for the proxy's root certificate.

Do yarn and pnpm need separate settings?

They run on Node.js, so NODE_EXTRA_CA_CERTS works for all of them. Each also has its own CA setting (for example yarn's cafile and Yarn Berry's caFilePath), which you only need if you prefer per-tool configuration.

How do I check which registry npm is using?

Run npm config get registry. A typo in a mirror URL or a stale project-level .npmrc pointing at an old internal registry is a common hidden cause.

Sources

  1. npm config (cafile, ca, strict-ssl, registry)
  2. Node.js command-line options (NODE_EXTRA_CA_CERTS)
  3. Node.js TLS (SSL) documentation