Error message
PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
Also printed as
- javax.net.ssl.SSLHandshakeException: (certificate_expired) PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
JDK 21 and later put the TLS alert in front: "(certificate_expired) PKIX path validation failed: …". The root cause line is "java.security.cert.CertificateExpiredException: NotAfter: <date>" (or CertificateNotYetValidException: NotBefore: <date>) in the JVM's time zone.
Java (JSSE) — SSLHandshakeException caused by CertPathValidatorException / CertificateExpiredException
What it means
Java built a certificate path to a trusted anchor, but validating it failed the date check: a certificate in the path is outside its validity period at the JVM's current time. "Path validation" (not "path building") means trust was fine; the dates were not. The nested CertificateExpiredException or CertificateNotYetValidException names the offending boundary.
Why it happens
The server's certificate (or intermediate) expired
commonRenewal did not happen or the renewed certificate is not deployed on the endpoint Java talks to (often an internal load balancer or a Java server with its own keystore).
The chain was built through an expired certificate in a custom trust store
occasionalTrust stores that pin an old intermediate or a server certificate directly keep validating against it after it expires.
The JVM host's clock is wrong
occasionalVirtual machines and containers whose host clock drifted can make current certificates look expired or not yet valid.
A freshly issued certificate and a clock that is behind
rareCertificates valid from "now" fail on clients a few minutes behind; most CAs backdate notBefore slightly for this reason, private CAs often do not.
How to fix it
- 1.
Read the innermost cause
The NotAfter or NotBefore date tells you whether a certificate expired or the clock is off.
text Caused by: java.security.cert.CertificateExpiredException: NotAfter: Tue Apr 01 00:00:00 UTC 2025 -> a certificate in the chain expired on that date Caused by: java.security.cert.CertificateNotYetValidException: NotBefore: ... -> not valid yet: check the clock of this machine - 2.
Check every certificate the server sends
Print the end date of each certificate in the served chain; replace whichever expired.
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts 2>/dev/null \ | awk '/BEGIN CERT/{n++; f="c" n ".pem"} /BEGIN CERT/,/END CERT/{print > f}' for f in c*.pem; do openssl x509 -in "$f" -noout -subject -enddate; done - 3.
Clean up custom trust stores
List the trust store's entries with their validity and remove or replace expired certificates that were pinned there.
bash # Expired or pinned certificates in a custom trust store keytool -list -v -keystore app-truststore.p12 -storepass changeit | grep -E 'Alias name|Valid until|Owner' keytool -delete -alias old-corp-root -keystore app-truststore.p12 -storepass changeit