Error message
code: 'DEPTH_ZERO_SELF_SIGNED_CERT'
Also printed as
- self-signed certificate; if the root CA is installed locally, try running Node.js with --use-system-ca
- DEPTH_ZERO_SELF_SIGNED_CERT
Node.js 24.22 prints the message as "self-signed certificate; if the root CA is installed locally, try running Node.js with --use-system-ca"; older releases print just "self-signed certificate" ("self signed certificate" before Node.js 17). The code is the stable part to search for.
Node.js tls / https / fetch — error.message "self-signed certificate" (OpenSSL X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, 18)
What it means
The server's certificate is self-signed (it is its own issuer, "depth zero" of the chain) and it is not in Node.js's trusted set. Node.js reports it with the message "self-signed certificate" and the code DEPTH_ZERO_SELF_SIGNED_CERT. Typical for local development servers, internal tools and services that still use the certificate generated at installation.
Why it happens
A local HTTPS server with a generated certificate
commonDev servers (Vite or webpack with https, local API gateways, docker-compose stacks) create a self-signed certificate that Node.js scripts, tests and SSR code do not trust.
Internal tools and appliances
commonSelf-hosted services (Jenkins, Grafana, Elasticsearch, router or NAS admin pages) that were never given a CA-issued certificate.
A proxy serves its built-in default certificate
occasionalIngress controllers and reverse proxies present a self-signed default certificate when no configured certificate matches the requested name.
How to fix it
- 1.
Trust this one certificate for one agent
Pass the server's certificate as ca. Only this certificate is accepted, hostname and validity checks stay on; note that ca replaces the default roots for this agent.
js // Trust exactly this certificate for this agent (hostname and dates are still checked) import https from "node:https"; import fs from "node:fs"; const agent = new https.Agent({ ca: fs.readFileSync("localhost.pem") }); https.get("https://localhost:8443/", { agent }, (res) => res.resume()); - 2.
Add the certificate for the whole process
NODE_EXTRA_CA_CERTS works for https, tls and fetch() alike and does not require code changes.
bash # Whole process, including fetch(): add the certificate to the trusted set NODE_EXTRA_CA_CERTS=./localhost.pem node app.js - 3.
Use a local CA for development
A local root trusted once (mkcert, step-ca) issues properly signed certificates for every dev host and avoids per-certificate exceptions.
bash # Development: a local CA (mkcert) instead of one-off self-signed certificates mkcert -install && mkcert localhost 127.0.0.1 NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" node app.js - 4.
Temporary diagnostic: rejectUnauthorized: false
Accepts any certificate on that agent, including an attacker's. Acceptable only for a quick local check; never in code that ships.
js // Temporary diagnostic in a test only: accepts ANY certificate on this agent const agent = new https.Agent({ rejectUnauthorized: false });
Related errors
self-signed certificate in certificate chainNode.js tls / https / fetchnpm error code DEPTH_ZERO_SELF_SIGNED_CERTnpm (Node.js)curl: (60) SSL certificate problem: self-signed certificatecurl (OpenSSL backend)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certifi…Python ssl module (OpenSSL)