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