How to fix Error: SSL: CERTIFICATE_VERIFY_FAILED (SSL protocol error) in Node.js

Node.jsINTERMEDIATEHIGHUpdated Dec 9, 2025· 225 views

SSL protocol errors occur when Node.js cannot verify an HTTPS server's certificate. This happens due to missing intermediate certificates, self-signed certificates, expired certificates, or incorrect system time. Learn how to diagnose and fix certificate verification failures safely.

Quick fix

Fixes CERTIFICATE_VERIFY_FAILED

date
  1. Verify the system time is correct
  2. Check if the certificate is expired
  3. Download the server's certificate chain
  4. Use NODE_EXTRA_CA_CERTS to include additional CA certificates
node.js — error
date
Error: SSL: CERTIFICATE_VERIFY_FAILED (SSL protocol error)

What this error means

This error occurs when your Node.js application attempts to make an HTTPS request (or establish a TLS connection) but cannot verify the server's SSL/TLS certificate. Node.js validates certificates by checking the complete certificate chain: the server certificate, any intermediate certificates, and the root certificate. If any part of this chain is missing, improperly configured, or issued by an untrusted Certificate Authority, Node.js rejects the connection. The error does not mean the certificate is necessarily invalid—it means your system cannot establish trust in the certificate through the standard verification process. This is a security feature that prevents man-in-the-middle (MITM) attacks and other certificate-based threats.

Typical symptoms

  • HTTPS requests fail with "CERTIFICATE_VERIFY_FAILED" error
  • fetch() or http.request() calls to specific servers always fail
  • Error occurs in development or testing environments but not in production
  • API calls to servers with self-signed or internally-signed certificates fail
  • Certificate errors appear after system time changes or clock drift
  • Intermediate CA certificates are missing from the server's configuration

Common causes

  1. Missing intermediate certificates in the server's certificate chain
  2. Self-signed certificate not added to the system or Node.js trust store
  3. Certificate issued by a private or corporate CA not recognized by default root CAs
  4. System clock is incorrect or significantly out of sync (certificate appears not-yet-valid)
  5. Expired SSL/TLS certificate on the server
  6. Server misconfigured to not send the full certificate chain
  7. Node.js version lacks updated CA certificates or modern TLS support
  8. Corporate proxy or antivirus software intercepting SSL connections

How to fix "Error: SSL: CERTIFICATE_VERIFY_FAILED (SSL protocol error)"

1Verify the system time is correct

SSL certificates have validity periods (not-before and not-after dates). If your system clock is significantly wrong, valid certificates may appear expired or not-yet-valid.

Check current time:

bash
date

If the time is incorrect, sync your system clock using NTP (Network Time Protocol):

Linux/macOS:

bash
sudo ntpdate -s time.nist.gov
# or
sudo timedatectl set-ntp true

Windows:

bash
w32tm /resync

Restart your Node.js application after correcting the time.

2Check if the certificate is expired

Verify the expiration date of the server's certificate using OpenSSL:

bash
openssl s_client -connect example.com:443 -showcerts 2>/dev/null | grep -A 5 "notAfter"

Or for a specific port:

bash
echo | openssl s_client -connect api.example.com:8443 2>/dev/null | openssl x509 -noout -dates

If the certificate has expired, the server administrator must renew it. If it's a self-signed certificate you control, generate a new one with an extended validity period:

bash
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
3Download the server's certificate chain

Get the full certificate chain from the server:

bash
openssl s_client -connect example.com:443 -showcerts 2>/dev/null > fullchain.pem

This will output all certificates in the chain. Save this file for the next steps.

Alternatively, download just the certificate using a web browser (click the padlock icon) or use:

bash
openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -outform PEM > server-cert.pem
4Use NODE_EXTRA_CA_CERTS to include additional CA certificates

For self-signed or internal CA certificates, tell Node.js to trust them by setting the NODE_EXTRA_CA_CERTS environment variable:

Linux/macOS:

bash
export NODE_EXTRA_CA_CERTS=/path/to/ca-cert.pem
node your-app.js

Windows (PowerShell):

powershell
$env:NODE_EXTRA_CA_CERTS = "C:\path\to\ca-cert.pem"
node your-app.js

Windows (Command Prompt):

cmd
set NODE_EXTRA_CA_CERTS=C:\path\to\ca-cert.pem
node your-app.js

If you have multiple CA certificates, concatenate them into a single file:

bash
cat ca1.pem ca2.pem ca3.pem > ca-bundle.pem
export NODE_EXTRA_CA_CERTS=/path/to/ca-bundle.pem
node your-app.js

This is the recommended approach for corporate or development environments with internal CAs.

5Configure certificate in your Node.js code (optional)

For more control, you can also configure certificates directly in your Node.js code:

javascript
import https from 'https';
import fs from 'fs';

const ca = fs.readFileSync('/path/to/ca-cert.pem', 'utf8');

const options = {
  hostname: 'api.example.com',
  port: 443,
  path: '/endpoint',
  method: 'GET',
  ca: ca,  // Add the CA certificate
};

const req = https.request(options, (res) => {
  res.on('data', (chunk) => {
    console.log('Received:', chunk.toString());
  });
});

req.on('error', (err) => {
  console.error('Request failed:', err.message);
});

req.end();

For fetch (Node.js 18+):

javascript
import https from 'https';
import fs from 'fs';

const ca = fs.readFileSync('/path/to/ca-cert.pem', 'utf8');
const agent = new https.Agent({ ca });

const response = await fetch('https://api.example.com/endpoint', {
  agent,
});

For axios:

javascript
import https from 'https';
import fs from 'fs';
import axios from 'axios';

const ca = fs.readFileSync('/path/to/ca-cert.pem', 'utf8');
const httpsAgent = new https.Agent({ ca });

axios.get('https://api.example.com/endpoint', {
  httpsAgent,
});
6Update Node.js and dependencies

Outdated Node.js versions may have incomplete or outdated CA certificate bundles. Update to the latest stable release:

bash
# Check current version
node --version

# Update Node.js (use nvm, brew, or download from nodejs.org)
nvm install node  # if using nvm
# or
brew upgrade node  # if using Homebrew

# Update npm packages
npm update
npm audit fix

After updating, restart your application.

7Add self-signed certificate to system trust store (permanent solution)

For development environments, you can permanently add a self-signed certificate to your system's trusted CA store:

Linux (Debian/Ubuntu):

bash
sudo cp ca-cert.pem /usr/local/share/ca-certificates/ca-cert.crt
sudo update-ca-certificates

macOS:

bash
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca-cert.pem

Windows:
Right-click the .pem or .crt file → Install Certificate → Select "Local Machine" → Place in "Trusted Root Certification Authorities"

After adding, restart Node.js to apply the changes.

Advanced notes

Corporate Proxies and Antivirus Software:
Some corporate environments use SSL inspection (decrypting HTTPS traffic to scan it). This replaces the server's certificate with a proxy certificate, causing verification failures. If your IT department has deployed such tools, they should provide a root CA certificate to add to NODE_EXTRA_CA_CERTS.

Intermediate Certificate Chain:
The complete certificate chain must be in the correct order: server certificate → intermediate CA(s) → root CA. If your server is only sending the server certificate without intermediates, the verification will fail. The server administrator must configure it to send the full chain (using fullchain.pem rather than just the leaf certificate).

Self-Signed vs. CA-Signed Certificates:
Self-signed certificates are valid for internal testing but should never be used in production without explicit trust configuration. In production, always use certificates from a recognized public CA (Let's Encrypt, DigiCert, etc.).

Disabling SSL Verification (Not Recommended):
While Node.js allows disabling certificate verification with rejectUnauthorized: false, this should only be done temporarily in development:

javascript
const agent = new https.Agent({ rejectUnauthorized: false });

Never use this in production as it removes all protection against MITM attacks.

Debugging Certificate Issues:
Enable verbose TLS debugging with:

bash
NODE_DEBUG=tls node your-app.js 2>&1 | grep -i cert

Certificate Rotation:
For production systems, implement automatic certificate renewal (e.g., using Let's Encrypt with certbot or similar tools) to prevent expiration-related errors.

Frequently asked questions

What does "CERTIFICATE_VERIFY_FAILED" mean?
js application attempts to make an HTTPS request (or establish a TLS connection) but cannot verify the server's SSL/TLS certificate. js validates certificates by checking the complete certificate chain: the server certificate, any intermediate certificates, and the root certificate. js rejects the connection.
How do I fix "CERTIFICATE_VERIFY_FAILED"?
SSL protocol errors occur when Node.js cannot verify an HTTPS server's certificate. This happens due to missing intermediate certificates, self-signed certificates, expired certificates, or incorrect system time. Learn how to diagnose and fix certificate verification failures safely.
What causes "CERTIFICATE_VERIFY_FAILED"?
Missing intermediate certificates in the server's certificate chain Self-signed certificate not added to the system or Node.js trust store Certificate issued by a private or corporate CA not recognized by default root CAs
Is the "CERTIFICATE_VERIFY_FAILED" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading