Skip to content
Latchkey

OpenSSL "verify error: certificate has expired" in CI

OpenSSL compared the certificate's validity window against the current time and found it past notAfter. There are two real causes in CI: the certificate genuinely expired, or the runner clock is skewed far enough that a valid certificate looks expired. Check the runner date first, because a wrong clock produces the exact same error.

What this error means

openssl or a client fails with "verify error:num=10:certificate has expired" and "Verify return code: 10". The same endpoint may work from a machine with a correct clock.

Terminal
depth=0 CN = example.com
verify error:num=10:certificate has expired
notAfter=Jun  1 00:00:00 2026 GMT
Verify return code: 10 (certificate has expired)

Common causes

The certificate is genuinely past its expiry

The endpoint's certificate reached its notAfter date and was not renewed, so every client rejects it.

Runner clock skew makes a valid cert look expired

A container or runner with a badly wrong system clock evaluates a currently-valid certificate as expired (or not yet valid).

How to fix it

Check the runner clock and the cert dates

  1. Print the runner date and compare it to real time.
  2. Read the certificate's notBefore/notAfter to see if it is truly expired.
  3. If the clock is wrong, fix time sync; if the cert is expired, renew it.
Terminal
date -u
echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates

Renew the expired certificate

If the certificate really expired, reissue and deploy a fresh one on the endpoint; no client-side flag fixes an expired server certificate.

How to prevent it

  • Keep runner clocks synced so validity windows are evaluated correctly.
  • Monitor certificate expiry and automate renewal well before notAfter.
  • Alert on certificates nearing expiry so CI never hits the wall.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →