An “untrusted certificate” message in Node.js can mean three different things: the certificate chain is not accepted by the connection’s trust configuration, the certificate was issued for a different name than the one you requested, or the TLS handshake failed before the client could reach an authorization result at all. Each has a different fix, and changing the CA list only helps one of them. Start by identifying which stage failed, then check the matching validation step.
Why the error text alone is not enough
Node.js reports TLS problems through several channels: error codes and messages on the socket, the authorized and authorizationError properties on a TLS socket, and events such as tlsClientError on the server side. The exact message, the Node.js release, the OpenSSL build bundled with it, the platform, and whether you used the https module or tls.connect() all change how you should read the failure. Record those details before deciding on a cause. The official reference for these behaviors is the Node.js TLS (SSL) documentation.
As an Amazon Associate I earn from qualifying purchases.
Three problems that share one symptom
| Problem | Validation step that failed | When it happens | First thing to check |
|---|---|---|---|
| 1. Chain not trusted | Whether the peer certificate chains to a CA in the socket’s trust configuration | After a secure connection is established; the result appears in socket authorization state | The ca option, the issuer chain the server sends, and whether the CA is the one you intended to trust |
| 2. Hostname not matched | Whether the certificate is issued to the requested hostname (identity check) | Checked only after the other certificate checks, including trusted-CA issuance, pass | The exact host or IP you passed, the certificate’s names, and any servername override |
| 3. Handshake or setup failure | No authorization result exists yet because negotiation or connection setup did not complete | Before a secure connection is established | The error code, whether the secure connection event was reached, SNI, and protocol compatibility |
Problem 1: the certificate chain is not trusted
The client must decide whether the server’s certificate chains to a certificate authority in the trust configuration used by that connection. Node exposes the result: tlsSocket.authorized is true when the peer certificate was signed by one of the CAs specified for that socket, and false otherwise. tlsSocket.authorizationError gives the reported reason.
When this is the problem, the correct response is to confirm that the certificate and its chain are the ones you expect, then supply the issuing CA through the connection’s trust settings. In a controlled environment with a private or self-signed server certificate, the Node.js documentation shows passing that certificate as the ca option. Pass the trust anchor you actually intend to rely on, not a broad or unverified file.
#1 Best Overall
Problem 2: the certificate is for a different name
Trust and identity are separate checks. tls.checkServerIdentity(hostname, cert) verifies that the certificate is issued to the requested hostname. A certificate can chain to a fully trusted CA and still fail here, for example when a load balancer, shared proxy, or internal service presents a certificate for another name.
Compare the hostname your code passes with the names in the certificate. Watch for these common mismatches:
Rank #2
- A URL that uses an IP address while the certificate lists only DNS names.
- A staging host name used against a production certificate, or the reverse.
- A
servernamevalue that differs from the host you connect to.
Adding a CA does not fix a wrong identity. If the names do not match, the correct fix is to connect to the right name or have the certificate reissued for the name you use.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Problem 3: the handshake failed before authorization
Some failures happen before the client has a secure connection and before any authorization result exists. In that case, authorized and authorizationError do not describe the failure, so reasoning from them can send you in the wrong direction.
Rank #3
A frequent cause with raw sockets is SNI. The https module enables Server Name Indication automatically, but tls.connect() does not enable it by default. A server that hosts several names may then return a default certificate for a different site, which looks exactly like a certificate problem. The setup mistake is the missing name in the handshake. When the server depends on SNI, set servername to the intended DNS name.
On the server side, the tlsClientError event reports errors that occur before secure establishment, which is a useful place to confirm that a handshake, rather than a certificate check, failed. The Node.js reference does not provide a complete mapping from every OpenSSL error code to these three categories, so treat a code name as a lead to verify on your own Node.js and OpenSSL version rather than as a settled diagnosis.
Rank #4
A minimal diagnostic script
This script reports the error code and message when the connection fails, and the authorization state when it succeeds. It does not change any verification setting.
const tls = require('node:tls');
const socket = tls.connect({
host: 'api.example.internal',
port: 443,
servername: 'api.example.internal'
}, () => {
console.log('authorized:', socket.authorized);
console.log('authorizationError:', socket.authorizationError);
socket.end();
});
socket.on('error', (err) => {
console.error('code:', err.code);
console.error('message:', err.message);
});
Replace the host and port with your target. Add a ca option only when you have confirmed the CA is the one you intend to trust.
Diagnostic sequence
- Record the Node.js version (
node --version), platform, whether you usehttpsortls.connect(), the target host and port, and the complete error code and message. - Decide whether the connection reached a secure state. If it did not, investigate SNI,
servername, and protocol compatibility first. - If a TLS socket exists, read
authorizedandauthorizationError. Afalsevalue with a chain-related reason points to Problem 1. - For a chain problem, verify the certificate chain the server presents and the CA configuration you pass in. Do not add a CA you have not verified.
- For an identity problem, compare the hostname you check with the names on the certificate, and fix the host or the certificate.
- For
tls.connect(), confirm thatservernameis set to the intended DNS name when the server uses SNI. - Re-run the script after each change, and confirm that the authorization result or error changes as expected.
What not to do
- Do not set
rejectUnauthorizedtofalseto make the error go away. The default verifies the server certificate against the supplied CAs, and disabling it removes the check that protects the connection. It is not a diagnosis. - Do not treat a hostname mismatch as a trust problem and widen the CA list to fix it.
- Do not read a handshake failure as a completed authorization result.
Once the failing stage is known, the fix is usually narrow: correct the trust anchor, the hostname, or the SNI name. Keep verification enabled while you do so.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




