- Node.js
- Exact text checked with the real tool
CERT_HAS_EXPIRED
Also seen in: npm, yarn, axios, fetch (undici), Electron
In one sentence
A certificate in the server's chain is past its end date by your machine's clock: usually the server's certificate was not renewed or reloaded; sometimes the clock is wrong.
Where you see it
In Node.js when you call an HTTPS server with https.request, fetch, axios or another client, and in npm and yarn. The code comes from OpenSSL’s verify error 10; Node.js lists it in its TLS documentation as “Certificate has expired”.
TypeError: fetch failed
at node:internal/deps/undici/undici:13510:13
at process.processTicksAndRejections (node:internal/process/task_queues:105:5) {
[cause]: Error: certificate has expired
at TLSSocket.onConnectSecure (node:_tls_wrap:1679:34)
at TLSSocket.emit (node:events:507:28)
at TLSSocket._finishInit (node:_tls_wrap:1078:8)
at ssl.onhandshakedone (node:_tls_wrap:864:12) {
code: 'CERT_HAS_EXPIRED'
}
}
With https.get or axios, the same Error: certificate has expired with code: 'CERT_HAS_EXPIRED' is the error itself; with fetch, look in [cause]. npm prints:
npm error code CERT_HAS_EXPIRED
npm error errno CERT_HAS_EXPIRED
npm error request to https://registry.example.com/left-pad failed, reason: certificate has expired
Older npm versions start these lines with npm ERR!. A certificate that is not valid yet gives CERT_NOT_YET_VALID (“certificate is not yet valid”).
What it means
Every certificate has a validity period: a notBefore and a notAfter date. Node.js checks every certificate in the certificate chain against the machine’s clock. For one of them, the current time is past notAfter, so Node.js stops the connection, even if everything else is correct. Usually the server’s own certificate expired; sometimes the client’s clock is wrong.
Likely causes
The server’s certificate expired
Confirm what the server sends right now:
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -dates
subject=CN=api.example.com
notBefore=Jan 1 00:00:00 2026 GMT
notAfter=Apr 1 00:00:00 2026 GMT
Fix: renew the certificate, install it with its full chain, and reload the server. If it is not your server, tell its owner; there is nothing safe to change on the client. For a Node.js server you run, the new files take effect only after the process restarts or calls server.setSecureContext() with them.
Public TLS certificates may be valid for at most 200 days since 15 March 2026, and for at most 47 days from 15 March 2029. Renew automatically and monitor what each endpoint serves: How to check when a certificate expires, and monitor it.
It was renewed, but the old certificate is still served
Common after a manual renewal or a failed reload. Compare the file with what the server sends:
openssl x509 -in /etc/ssl/api.example.com/fullchain.pem -noout -enddate
If the file is newer, reload or restart the service. Behind a load balancer, test each backend directly, because one node may still have the old certificate. In Kubernetes, check which Secret the ingress really uses; see How to automate certificates in Kubernetes with cert-manager.
An intermediate or old cross-signed certificate in the chain expired
If the server’s own certificate is valid, look at the other certificates it sends:
openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null | grep -E '^ [0-9]+ s:|^ i:|NotAfter'
An expired intermediate left in the chain file must be replaced with the CA’s current chain (How to build the full chain file your server needs). Old clients can also build a path through an expired cross-signed certificate even when a valid path exists, as happened when DST Root CA X3, the older root that had cross-signed Let's Encrypt, expired, so devices that did not trust ISRG Root X1 began rejecting Let's Encrypt certificates (30 September 2021). Update Node.js on such clients.
The client’s clock is wrong
If a certificate that works everywhere else fails on one machine or container, check that machine’s time in UTC:
date -u
timedatectl status
Turn on time synchronisation (sudo timedatectl set-ntp true on systemd Linux, w32tm /resync on Windows). Virtual machines restored from snapshots and devices without a clock battery are typical.
Check yours
Paste the server’s certificate (the first BEGIN CERTIFICATE block from openssl s_client -showcerts). The decoder shows the validity dates and how many days are left or overdue.
Learn why
- Anatomy of an X.509 certificate: the validity fields.
- Inventory, expiry and renewal and ACME and the 47-day schedule.
- The same problem in OpenSSL: verify error:num=10:certificate has expired.
Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.