Introduction
The PKIX path building failed error occurs when Java's SSL implementation cannot build a trusted certificate chain to the server's certificate. Unlike some HTTP clients, Java requires the full chain to be trusted in its keystore, and self-signed or corporate CA-signed certificates are not trusted by default.
This is a common issue when connecting to internal services, using self-signed certificates, or working behind corporate TLS proxies.
Symptoms
- HTTPS connection fails with "javax.net.ssl.SSLHandshakeException: PKIX path building failed"
- Caused by: "sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path"
- Same URL works in browser but Java code throws SSL exception
Common Causes
- Server certificate is signed by a CA not in Java's default truststore
- Self-signed certificate is used on the target server
- Corporate TLS intercepting proxy re-signs certificates with an internal CA
Step-by-Step Fix
- 1.Import the certificate into Java truststore: Add the server's CA certificate to cacerts.
- 2.```bash
- 3.# Download the server certificate:
- 4.echo | openssl s_client -connect api.example.com:443 -showcerts 2>/dev/null | \
- 5.openssl x509 -out server.crt
# Import into Java truststore: sudo keytool -importcert \ -alias api-example-com \ -file server.crt \ -keystore $JAVA_HOME/lib/security/cacerts \ -storepass changeit \ -noprompt ```
- 1.Use a custom truststore for the application: Don't modify the global cacerts.
- 2.```bash
- 3.# Create a custom truststore:
- 4.keytool -importcert \
- 5.-alias my-ca \
- 6.-file corporate-ca.crt \
- 7.-keystore app-truststore.jks \
- 8.-storepass mypassword \
- 9.-noprompt
# Use it at runtime: java -Djavax.net.ssl.trustStore=/path/to/app-truststore.jks \ -Djavax.net.ssl.trustStorePassword=mypassword \ -jar myapp.jar ```
- 1.Configure truststore in Spring Boot: Set truststore properties in application.yml.
- 2.```yaml
- 3.# application.yml:
- 4.server:
- 5.ssl:
- 6.trust-store: classpath:truststore.jks
- 7.trust-store-password: ${TRUSTSTORE_PASSWORD}
- 8.trust-store-type: JKS
- 9.
` - 10.Debug SSL handshake to identify the issue: Enable SSL debugging to see exactly what fails.
- 11.```bash
- 12.# Enable SSL debugging:
- 13.java -Djavax.net.debug=ssl:handshake -jar app.jar
# Output shows the certificate chain: # *** Certificate chain # chain [0] = [ # Subject: CN=api.example.com # Issuer: CN=Corporate Internal CA # ] ```
Prevention
- Use proper CA-signed certificates from trusted authorities (Let's Encrypt, etc.)
- Maintain application-specific truststores instead of modifying the global cacerts
- Include truststore setup in infrastructure provisioning scripts
- Enable SSL debugging in staging environments to catch trust issues early