This error occurs when Node.js attempts an HTTPS connection to a server whose SSL/TLS certificate does not include the hostname or IP address being used in the request. Node.js validates that the connection target matches the Subject Alternative Names (SANs) in the certificate for security.
This error indicates a certificate validation failure during TLS/SSL handshake. When Node.js makes an HTTPS request, it verifies that the hostname or IP address in the URL matches one of the domains listed in the server's SSL certificate's Subject Alternative Names (SANs) field or Common Name (CN). The error serves as a security measure to prevent man-in-the-middle attacks. If the hostname doesn't match, Node.js rejects the connection by default to protect your application from connecting to potentially malicious servers. This commonly occurs when connecting to servers with self-signed certificates, using IP addresses instead of domain names, accessing services through proxies or load balancers, or when certificates were issued for different domains than the one being requested.
First, check what hostname you're connecting to and what the certificate expects:
# Check certificate details using OpenSSL
openssl s_client -connect your-server.com:443 -servername your-server.com < /dev/null 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"This will show you the SANs in the certificate. Ensure your connection hostname matches one of these entries.
If you're using an IP address or incorrect hostname, update your code to use the hostname that matches the certificate:
// Bad - using IP address
const response = await fetch('https://192.168.1.100/api');
// Good - using proper hostname
const response = await fetch('https://api.example.com/api');Update your environment variables, configuration files, or code to use the correct hostname.
If you must connect using a different hostname than the certificate expects (e.g., through a proxy), specify the servername option:
const https = require('https');
const options = {
hostname: '192.168.1.100',
port: 443,
path: '/api',
method: 'GET',
servername: 'api.example.com', // Certificate's expected name
};
https.request(options, (res) => {
// Handle response
}).end();For axios:
const axios = require('axios');
const https = require('https');
const agent = new https.Agent({
servername: 'api.example.com'
});
axios.get('https://192.168.1.100/api', { httpsAgent: agent });If using self-signed certificates in development, add the CA certificate to Node.js:
const https = require('https');
const fs = require('fs');
const agent = new https.Agent({
ca: fs.readFileSync('./path/to/ca-certificate.pem')
});
// For fetch
fetch('https://localhost:8443/api', { agent });
// For axios
axios.get('https://localhost:8443/api', { httpsAgent: agent });Or set the environment variable:
export NODE_EXTRA_CA_CERTS=/path/to/ca-certificate.pemWARNING: Only use this in development/testing. Never in production.
For quick testing, you can disable certificate validation:
const https = require('https');
const agent = new https.Agent({
rejectUnauthorized: false
});
// For fetch
fetch('https://localhost:8443/api', { agent });
// For axios
axios.get('https://localhost:8443/api', { httpsAgent: agent });Or environment variable:
NODE_TLS_REJECT_UNAUTHORIZED=0 node app.jsThis makes your application vulnerable to man-in-the-middle attacks. Use only for local development.
If you control the server, regenerate the certificate to include all necessary hostnames:
# Example: Creating a certificate with multiple SANs using OpenSSL
openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 \
-subj "/CN=api.example.com" \
-addext "subjectAltName=DNS:api.example.com,DNS:localhost,IP:127.0.0.1,IP:192.168.1.100"For Let's Encrypt certificates, ensure all domains are included in the certificate request:
certbot certonly --standalone -d api.example.com -d www.example.comCustom checkServerIdentity Function
For advanced scenarios, you can implement custom hostname verification logic:
const tls = require('tls');
const agent = new https.Agent({
checkServerIdentity: (hostname, cert) => {
// Custom validation logic
if (hostname === 'trusted-internal-service') {
return undefined; // Accept connection
}
// Fall back to default validation
return tls.checkServerIdentity(hostname, cert);
}
});Wildcard Certificate Limitations
Wildcard certificates (*.example.com) only match one level of subdomain:
- *.example.com matches api.example.com ✓
- *.example.com does NOT match sub.api.example.com ✗
Proxy and Load Balancer Considerations
When connecting through proxies or load balancers, the SNI (Server Name Indication) must be set correctly. Some HTTP clients don't automatically set SNI when connecting to IP addresses, causing this error even if the certificate is valid.
Common Cloud Service Errors
AWS S3, DigitalOcean Spaces, and similar services require exact endpoint formatting. Using the wrong endpoint format (e.g., including bucket name in hostname incorrectly) triggers this error. Always follow the service's official endpoint documentation.
Node.js Version Differences
Older Node.js versions (< 0.11.x) had less strict certificate validation. Modern versions enforce strict SAN matching for security. If legacy code suddenly fails after a Node.js upgrade, this is likely the cause.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams