Error message
Hostname/IP does not match certificate's altnames: Host: api.example.com. is not in the cert's altnames: DNS:www.example.com
Also printed as
- Hostname/IP does not match certificate's altnames: IP: 127.0.0.1 is not in the cert's list:
- code: 'ERR_TLS_CERT_ALTNAME_INVALID'
- ERR_TLS_CERT_ALTNAME_INVALID
The host and the altnames list are filled in per failure. For IP addresses the wording is "Hostname/IP does not match certificate's altnames: IP: <address> is not in the cert's list: <entries>". npm shows it as "npm error code ERR_TLS_CERT_ALTNAME_INVALID".
Node.js tls.checkServerIdentity() — code ERR_TLS_CERT_ALTNAME_INVALID
What it means
The certificate chain is trusted, but tls.checkServerIdentity() found no Subject Alternative Name matching the host Node.js connected to. The message lists both sides: the host you asked for and the names the certificate actually carries, so the mismatch is visible at a glance. The Common Name is ignored when the certificate has a SAN extension.
Why it happens
The certificate does not list this name
commonA certificate for www.example.com does not cover api.example.com or the bare domain; wildcards cover a single label only.
Connecting by IP, localhost or a container alias
commonURLs such as https://127.0.0.1:8443 or https://backend:443 inside docker-compose ask for names the certificate does not contain; IPs need IP SAN entries.
Only the Host header was changed, not the TLS name
occasionalSetting headers.host to the right name while connecting by IP does not change what Node.js verifies; the servername option (or the URL host) decides which name is checked and sent as SNI.
The server returned its default certificate
occasionalA reverse proxy without a configuration for this name answers with the certificate of another site.
How to fix it
- 1.
List the certificate's names
Compare subjectAltName with the host you connect to.
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName - 2.
Reissue with every name in use
Add all DNS names and, where clients connect by address, IP entries.
bash openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com,IP:10.0.0.5" - 3.
Set servername when connecting by address
Keep the certificate's name in servername (and the Host header) and connect to the address; verification then uses the correct name instead of being switched off.
js // Connect to an address but verify the certificate's real name (also sent as SNI) import https from "node:https"; https.get({ host: "10.0.0.5", port: 443, path: "/", servername: "api.example.com", headers: { host: "api.example.com" } }, (res) => res.resume()); - 4.
Narrow exception with checkServerIdentity
For a legacy host whose certificate cannot be reissued yet, map one known alias to the certificate's name and delegate to tls.checkServerIdentity(). Never return undefined unconditionally: that disables the name check completely.
js // Narrow exception for a host you cannot reissue: accept one extra name, keep all other checks import https from "node:https"; import tls from "node:tls"; const agent = new https.Agent({ checkServerIdentity: (host, cert) => tls.checkServerIdentity(host === "legacy-alias.internal" ? "api.example.com" : host, cert), });
Related errors
npm error code ERR_TLS_CERT_ALTNAME_INVALIDnpm (Node.js)x509: certificate is valid for example.com, not api.example.comGo crypto/x509curl: (60) SSL: no alternative certificate subject name matches target hostname…curl (OpenSSL backend)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch,…Python ssl module (OpenSSL host check)