Error message
unable to verify the first certificate
Also printed as
- code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
- UNABLE_TO_VERIFY_LEAF_SIGNATURE
Recent Node.js releases (24.22 in our test) append "; if the root CA is installed locally, try running Node.js with --use-system-ca" to this message. With fetch() it appears as the cause of "TypeError: fetch failed"; axios and got show it as the error message with the same code.
Node.js tls / https / fetch — code UNABLE_TO_VERIFY_LEAF_SIGNATURE (OpenSSL X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, 21)
What it means
Node.js received only the server's own (leaf) certificate and could not find its issuer anywhere: not in the handshake and not among its trusted roots. Without the issuer it cannot even check the leaf's signature, hence "the first certificate". Almost always the server forgets to send its intermediate certificate; browsers mask this by downloading intermediates, Node.js never does.
Why it happens
The server does not send its intermediate certificate
commonA certificate file containing only the leaf (cert.pem instead of fullchain.pem, or a load balancer certificate uploaded without the chain). Even with the right root trusted, Node.js cannot bridge leaf and root, as the reproduction shows.
A private CA issued the leaf, and nothing in the chain is known
commonInternal services whose certificate comes from a company or self-made CA, served alone, produce the same code: Node.js knows neither the issuer nor anything above it.
The intermediate is in the file but not used
occasionalSome servers only send the first certificate of a file, or expect the chain in a separate setting (SSLCertificateChainFile in old Apache, a separate chain field in cloud load balancers). The intermediate exists on disk but never reaches the client.
How to fix it
- 1.
Check how many certificates the server sends
If only depth 0 appears and its issuer is an intermediate CA, the fix belongs on the server.
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' # Only " 0 s:" present, with an i: that is an intermediate -> the server must send that intermediate - 2.
Serve the full chain
Give the server a bundle with the leaf followed by every intermediate. For Node.js servers that is the cert option; for nginx ssl_certificate, for cloud load balancers the certificate chain field.
js // Node.js HTTPS server: pass leaf + intermediates as the cert import https from "node:https"; import fs from "node:fs"; https.createServer({ key: fs.readFileSync("server.key"), cert: fs.readFileSync("fullchain.pem"), // leaf first, then intermediate(s) }, handler).listen(443); - 3.
If you cannot change the server: add the intermediate on the client
NODE_EXTRA_CA_CERTS accepts intermediate certificates too and is read once at process start. Prefer fixing the server: every other client (mobile apps, partners) has the same problem.
bash # When you cannot fix the server: trust the missing intermediate on the client too NODE_EXTRA_CA_CERTS=/etc/ssl/certs/issuing-ca.pem node app.js - 4.
Temporary diagnostic: disable verification for one run
NODE_TLS_REJECT_UNAUTHORIZED=0 turns off certificate checks for every TLS connection in the process and prints a warning. Use it only to confirm the diagnosis; in production it lets anyone on the path read and alter the traffic.
bash # Temporary diagnostic only: disables certificate verification for the whole process NODE_TLS_REJECT_UNAUTHORIZED=0 node app.js
Related errors
unable to get local issuer certificateNode.js tls / https / fetchself-signed certificate in certificate chainNode.js tls / https / fetchnpm error code UNABLE_TO_VERIFY_LEAF_SIGNATUREnpm (Node.js)verify error:num=21:unable to verify the first certificateOpenSSL CLI (openssl s_client)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)