This error occurs when a Node.js TLS client refuses to connect because the server offers Diffie-Hellman key exchange parameters smaller than the minimum security threshold (typically 1024 bits). Modern OpenSSL versions reject weak DH groups to protect against cryptographic attacks like Logjam.
This error indicates that the TLS/SSL handshake failed because the server attempted to use Diffie-Hellman (DH) key exchange parameters that are too small to meet current security standards. Diffie-Hellman is a cryptographic protocol used to establish shared secrets over an insecure channel during TLS connections. Modern versions of OpenSSL (which Node.js uses for TLS) have minimum security requirements for DH parameters. OpenSSL 1.1.0 and later reject DH keys smaller than 1024 bits by default, and best practices recommend 2048 bits or higher. When a server offers weak DH parameters (512 or 768 bits), the Node.js client terminates the connection to prevent potential security vulnerabilities. This is a deliberate security measure introduced to protect against the Logjam attack, a cryptographic vulnerability that allows attackers to downgrade TLS connections and potentially decrypt traffic when weak DH groups are used.
First, verify which server is causing the issue. The error usually includes the hostname or IP address:
# Test the TLS connection
node -e "require('https').get('https://example.com', (res) => console.log('OK'))"If you see the DH key error, that server needs to be fixed. You can also use OpenSSL directly to test:
openssl s_client -connect example.com:443 -cipher "DHE"The best solution is to upgrade the server's DH parameters to at least 2048 bits. Generate new DH parameters:
openssl dhparam -out /path/to/dhparam.pem 2048Then configure your web server to use them. For Nginx:
ssl_dhparam /path/to/dhparam.pem;For Apache:
SSLOpenSSLConfCmd DHParameters /path/to/dhparam.pemFor Node.js TLS servers:
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
dhparam: fs.readFileSync('dhparam.pem')
};
tls.createServer(options, (socket) => {
// server code
});If you cannot control the server, you can temporarily lower the minimum DH size on the client side. Warning: This reduces security.
const https = require('https');
const tls = require('tls');
const options = {
hostname: 'example.com',
port: 443,
path: '/',
method: 'GET',
minDHSize: 512 // Lower threshold (not recommended for production)
};
https.get(options, (res) => {
console.log('Connected');
});Or set it globally:
process.env.NODE_OPTIONS = '--tls-min-dh-size=512';A more secure alternative is to disable DHE ciphers entirely and rely on ECDHE (Elliptic Curve Diffie-Hellman):
const https = require('https');
const options = {
hostname: 'example.com',
port: 443,
path: '/',
method: 'GET',
ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:!DHE'
};
https.get(options, (res) => {
console.log('Connected using ECDHE');
});This approach maintains strong security by avoiding weak DH groups altogether.
As a last resort for testing only, you can lower the OpenSSL security level. This should never be used in production.
In Docker:
FROM node:18
RUN sed -i "s/SECLEVEL=2/SECLEVEL=1/g" /etc/ssl/openssl.cnfOr set via environment variable:
export OPENSSL_CONF=/path/to/custom-openssl.cnfThis allows connections to servers with 1024-bit DH parameters but should only be temporary.
Logjam Vulnerability Context
The Logjam attack (CVE-2015-4000) demonstrated that 512-bit and 768-bit DH groups are vulnerable to downgrade attacks. An attacker with sufficient computational resources can break these weak groups and decrypt TLS traffic. This led to OpenSSL and other TLS implementations raising minimum DH size requirements.
Security Level Settings
OpenSSL 1.1.0 introduced security levels:
- Level 1: 80-bit security, allows 1024-bit DH (deprecated)
- Level 2: 112-bit security, requires 2048-bit DH (default)
- Level 3: 128-bit security, requires 3072-bit DH
Node.js typically defaults to Level 2, which is why 1024-bit DH parameters are rejected.
DH vs ECDHE Performance
ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) offers equivalent security with much smaller key sizes and better performance. A 256-bit ECDHE key provides roughly equivalent security to a 3072-bit DH key. Modern TLS configurations should prefer ECDHE over traditional DHE.
Cipher Suite Recommendations
Prefer cipher suites in this order:
1. ECDHE with AES-GCM (e.g., ECDHE-RSA-AES256-GCM-SHA384)
2. ECDHE with ChaCha20-Poly1305
3. Traditional DH with 2048+ bit parameters (legacy compatibility only)
Enterprise Considerations
In enterprise environments with legacy systems, a phased approach works best:
1. Audit all systems to identify those using weak DH parameters
2. Upgrade servers to 2048-bit DH parameters
3. Transition to ECDHE-only cipher suites
4. Remove DHE cipher support entirely once all clients are updated
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