Error message
unable to get local issuer certificate
Also printed as
- code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
- UNABLE_TO_GET_ISSUER_CERT_LOCALLY
With fetch() the message is the cause of "TypeError: fetch failed"; npm reports the same condition as "npm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY". If the server sends only its leaf, Node.js reports "unable to verify the first certificate" instead.
Node.js tls / https / fetch — code UNABLE_TO_GET_ISSUER_CERT_LOCALLY (OpenSSL X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 20)
What it means
The server sent a chain (leaf and intermediate), but the certificate at its top was issued by a root that Node.js does not trust. By default Node.js trusts only the Mozilla root list compiled into the binary, not the operating system's store, so a company root installed on the machine is invisible to it unless you tell Node.js to use it.
Why it happens
A company or private CA
commonInternal APIs, staging environments and service meshes use roots that are not in Node.js's bundled Mozilla list.
A TLS-inspecting proxy
commonOn company networks, intercepting proxies re-sign public sites with a company root; when the proxy sends only its issuing intermediate, Node.js reports this code rather than "self-signed certificate in certificate chain".
Node.js ignores the operating system's trust store by default
occasionalInstalling the root with update-ca-certificates, in the Windows store or the macOS Keychain fixes curl and browsers but not Node.js, unless --use-system-ca or NODE_USE_SYSTEM_CA=1 is used.
How to fix it
- 1.
NODE_EXTRA_CA_CERTS
Points Node.js at a PEM file whose certificates are added to the built-in roots. It is read once when the process starts, so exporting it inside a running app has no effect.
bash # Adds to Node's built-in roots; read once at start-up, so set it before node starts export NODE_EXTRA_CA_CERTS=/etc/ssl/private-ca/corp-root-ca.pem node app.js - 2.
Use the operating system's store
--use-system-ca (or NODE_USE_SYSTEM_CA=1 in the environment) makes Node.js trust the certificates trusted by the OS, which is what IT departments manage.
bash # Trust what the operating system trusts (Windows store, macOS Keychain, Linux bundle) node --use-system-ca app.js # or, for tools that start node themselves (npm scripts, CLIs): NODE_USE_SYSTEM_CA=1 npx some-cli - 3.
Set the default CA list in code
tls.setDefaultCACertificates() replaces the default list for later connections made by https, tls and fetch; combine the existing defaults with your root as shown.
js // In code, before the first request: keep the default roots and add yours. // Applies to https, tls and fetch. Available in current Node.js 22 and 24 releases. import tls from "node:tls"; import fs from "node:fs"; tls.setDefaultCACertificates([ ...tls.getCACertificates("default"), fs.readFileSync("/etc/ssl/private-ca/corp-root-ca.pem", "utf8"), ]); - 4.
Trust the root for one agent
The ca option of an agent or tls.connect() replaces the default roots for those connections, so include tls.rootCertificates if the same agent also talks to public hosts.
js // Per-agent trust: note that "ca" REPLACES the default roots, so append them import https from "node:https"; import tls from "node:tls"; import fs from "node:fs"; const agent = new https.Agent({ ca: [...tls.rootCertificates, fs.readFileSync("corp-root-ca.pem", "utf8")] }); https.get("https://api.example.com/", { agent }, (res) => res.resume());
Related errors
unable to verify the first certificateNode.js tls / https / fetchself-signed certificate in certificate chainNode.js tls / https / fetchnpm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLYnpm (Node.js)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)