Skip to content
ecdsa.com
Node.js tls.connect / fetchNode.js crypto

Error message

code: 'ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE'

Also printed as

  • ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE

The code mirrors OpenSSL's reason string: Node.js releases bundling OpenSSL 3.0 or 3.1 report ERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILURE (from "sslv3 alert handshake failure"); current releases with OpenSSL 3.5 report ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE. With https.request() the same alert appears as "write EPROTO … SSL alert number 40".

Node.js tls.connect / fetch — TLS alert 40 (handshake_failure) received from the server

What it means

The server answered Node.js's ClientHello with TLS alert 40 (handshake_failure) and closed the connection. It found no acceptable combination of cipher suite, key-exchange group and signature algorithm, or it requires a client certificate that was not sent. Node.js derives the error code from OpenSSL's reason text, which is why it contains "SSL/TLS".

Why it happens

How to fix it

  1. 1.

    Compare what both sides support

    Print Node.js's default cipher list and enumerate the server's suites; no overlap means the server must be updated.

    bash
    node -p "require('tls').getCiphers().length + ' suites; default list: ' + require('tls').DEFAULT_CIPHERS"
    nmap --script ssl-enum-ciphers -p 443 api.example.com   # what the server accepts
  2. 2.

    Send the client certificate

    Configure cert and key (or pfx) on the agent used for the mTLS endpoint.

    js
    // Mutual TLS: present the client certificate the server requires
    import https from "node:https";
    import fs from "node:fs";
    
    const agent = new https.Agent({ cert: fs.readFileSync("client.pem"), key: fs.readFileSync("client.key") });
    https.get("https://mtls.example.com/", { agent }, (res) => res.resume());
  3. 3.

    Server owners: offer current suites

    TLS 1.3 plus TLS 1.2 with ECDHE and AES-GCM or ChaCha20-Poly1305 works with every maintained Node.js release.

    text
    # Server side (nginx): TLS 1.3 + TLS 1.2 ECDHE with AEAD ciphers
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

Related errors

Browse the full signature error database