This error occurs when Node.js attempts an HTTPS connection to a server with an SSL/TLS certificate signed by a Certificate Authority (CA) that is not trusted or recognized. Node.js maintains a list of trusted root CAs, and when a certificate is signed by an unknown or self-signed CA, the connection is rejected.
This error indicates a TLS/SSL handshake failure during certificate validation. When Node.js establishes an HTTPS connection, it verifies the server's certificate by checking if it was signed by a trusted Certificate Authority (CA). The error occurs when: - The certificate was signed by a self-signed CA (not a recognized public CA) - The certificate chain is incomplete (missing intermediate certificates) - The CA certificate is not in Node.js's trusted certificate store - A corporate proxy or firewall is intercepting HTTPS traffic with its own CA - The certificate's issuer is not properly recognized by the system This is a security feature that prevents man-in-the-middle attacks by ensuring connections are only made to servers with valid, trusted certificates.
First, inspect the server's certificate to see what CA signed it:
# Check the certificate and its chain
openssl s_client -connect your-server.com:443 -showcerts < /dev/null 2>/dev/null
# Get certificate details
openssl s_client -connect your-server.com:443 -servername your-server.com < /dev/null 2>/dev/null | openssl x509 -noout -textLook for the "Issuer" field. If it's self-signed, it will show the same CN (Common Name) for both Subject and Issuer.
The most reliable solution for custom CAs. Save the CA certificate (in PEM format) to a file, then tell Node.js to trust it:
# For a single CA certificate
export NODE_EXTRA_CA_CERTS=/path/to/ca-certificate.pem
node your-app.js
# For multiple CA certificates, concatenate them into one file
cat cert1.pem cert2.pem > ca-bundle.pem
export NODE_EXTRA_CA_CERTS=/path/to/ca-bundle.pem
node your-app.jsThis variable can also be set in your deployment environment (GitHub Actions, Docker, cloud platforms, etc.).
For HTTPS requests, pass the CA certificate directly in the request options:
const https = require('https');
const fs = require('fs');
const ca = fs.readFileSync('/path/to/ca-certificate.pem');
const options = {
hostname: 'your-server.com',
port: 443,
path: '/api',
method: 'GET',
ca: ca // Pass the CA certificate
};
https.request(options, (res) => {
console.log('Connected successfully');
}).end();For axios:
const axios = require('axios');
const https = require('https');
const fs = require('fs');
const ca = fs.readFileSync('/path/to/ca-certificate.pem');
const agent = new https.Agent({ ca });
axios.get('https://your-server.com/api', { httpsAgent: agent });For fetch with custom agents:
import https from 'https';
import fs from 'fs';
const ca = fs.readFileSync('/path/to/ca-certificate.pem');
const agent = new https.Agent({ ca });
fetch('https://your-server.com/api', { agent });If the server is providing certificates but the chain is incomplete, download and concatenate them:
# Download the full certificate chain
openssl s_client -connect your-server.com:443 -showcerts < /dev/null 2>/dev/null > fullchain.pem
# Verify the chain is complete
openssl verify -CAfile fullchain.pem fullchain.pem
# Use it in Node.js
export NODE_EXTRA_CA_CERTS=/path/to/fullchain.pemThe chain should be ordered: server certificate, intermediate certificate(s), root certificate.
If the CA is already installed in your system's certificate store, run Node.js with:
node --use-system-ca app.jsThis tells Node.js to trust certificates from the operating system's CA store in addition to its own built-in CA certificates.
In Docker containers, system CAs may not be installed. Add certificates to the container:
FROM node:18
# Install CA certificates
RUN apt-get update && apt-get install -y ca-certificates
# Copy your custom CA
COPY ca-certificate.pem /usr/local/share/ca-certificates/
RUN update-ca-certificates
# Set Node.js to use system CAs
ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "app.js"]WARNING: Only use in development/testing. Never in production.
For quick testing with untrusted certificates:
# Environment variable
NODE_TLS_REJECT_UNAUTHORIZED=0 node app.jsIn code:
// Only for testing - NEVER use in production
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const https = require('https');
https.request(options, (res) => {
console.log('Connected (without validation)');
}).end();This disables all certificate validation and makes your application vulnerable to man-in-the-middle attacks.
Certificate Chain Debugging
Use these commands to understand certificate chains:
# View issuer information
openssl x509 -in certificate.pem -noout -issuer
# View entire certificate chain from server
openssl s_client -connect your-server.com:443 -showcerts
# Verify certificate validity
openssl x509 -in certificate.pem -noout -dates
# Check if certificate is self-signed
openssl x509 -in certificate.pem -noout -issuer -subject
# If Issuer and Subject are the same, it's self-signedCorporate Proxies and Firewalls
When behind a corporate proxy that intercepts HTTPS traffic with its own CA:
1. Obtain the proxy's CA certificate from your IT department
2. Set NODE_EXTRA_CA_CERTS to the proxy's CA
3. Some proxies also require setting HTTP_PROXY and HTTPS_PROXY environment variables
4. Configure npm with the corporate proxy: npm config set cafile /path/to/ca.pem
NPM and Git Behind Corporate Proxies
# Configure npm
npm config set cafile /path/to/ca.pem
# Configure git
git config --global http.sslCAInfo /path/to/ca.pemLet's Encrypt and Public CAs
If using a legitimate public CA (Let's Encrypt, DigiCert, etc.) and still getting this error:
1. The certificate chain may be incomplete on the server
2. Contact the server administrator to ensure they're serving the full certificate chain
3. They should configure their web server (nginx, Apache, etc.) to include intermediate certificates
4. For Let's Encrypt, this usually means using the full chain certificate (fullchain.pem, not cert.pem)
Self-Signed Certificate Generation
If you control the server and need to generate a self-signed certificate for testing:
# Generate a self-signed certificate valid for 365 days
openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 \
-subj "/CN=localhost"
# Use in Node.js
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Secure server');
}).listen(8443);Error: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process