← Debugging Guides

阅读中文版本

Node.js — unable to verify the first certificate

Resolve TLS verification errors in Node by fixing the CA trust and the presented chain, not by disabling verification.

intermediatedebuggingnodetls

Symptoms

  • Error: unable to verify the first certificate
  • Error: self-signed certificate in certificate chain
  • curl works but Node fails against the same host
  • The failure appears only in a corporate network

Possible causes

  • The server sends an incomplete chain missing an intermediate certificate
  • The CA is not in the Node trust store, which historically used its own bundle
  • A corporate proxy presents a certificate Node does not trust
  • The hostname does not match the certificate

Diagnosis steps

Inspect the chain the server sends

openssl s_client -connect host:443 -servername host -showcerts

Interpretation

A missing intermediate shows as an incomplete chain, which browsers may repair but Node may not.

Compare trust stores

node -p "process.env.NODE_EXTRA_CA_CERTS"

Interpretation

Setting NODE_EXTRA_CA_CERTS adds a CA bundle for Node, explaining differences from tools that read the system store.

Test with an explicit CA

NODE_EXTRA_CA_CERTS=/path/ca.pem node app.js

Interpretation

If this succeeds, the missing trust is the cause and the bundle should be installed for the environment.

Root cause

Node could not build a trusted chain to the server certificate because an intermediate was missing from the presented chain or the issuing CA was absent from the trust store Node uses.

Fix

Fix the server to send the full chain, and add the required CA to the environment trust, for example with NODE_EXTRA_CA_CERTS. Prefer correcting trust over disabling verification.

Verify the fix

Rerun the connection and confirm it succeeds without TLS errors, and confirm the certificate validates against the expected issuer.

Symptom walkthrough

An HTTPS request from Node fails with unable to verify the first certificate or self-signed certificate in certificate chain, while curl or a browser connects fine. The discrepancy usually comes from Node historically shipping its own CA bundle instead of the system store and from servers that omit an intermediate certificate, which browsers fetch but Node does not.

Fix in practice

Inspect the chain the server presents and fix it to include all intermediates. If the CA is legitimately private, add it to Node trust through NODE_EXTRA_CA_CERTS rather than rejecting all certificates. The goal is a complete, trusted chain, not disabled verification.

Verification

Reconnect and confirm success without TLS errors, then confirm the certificate validates against the expected issuer. A trusted chain with a working request proves the fix. Keeping the trust bundle aligned with the operating system avoids repeating this class of failure later.

Diagnostic commands

Check the behavior with commands like these:

openssl s_client -connect host:443 -servername host -showcerts
node -p "process.env.NODE_EXTRA_CA_CERTS"
NODE_EXTRA_CA_CERTS=/path/ca.pem node app.js