# Java PKIX path building failed: causes and fixes

> PKIX path building failed means the JVM could not chain the server certificate to a root in its truststore. Fix the server chain or import the right root.

Source: https://ssl.sh/errors/java-pkix-path-building-failed/
Last updated: 2026-11-10

**`PKIX path building failed ... unable to find valid certification path to requested target` means the JVM could not connect the server's certificate to any trusted root in its truststore.** The usual culprits are a missing intermediate on the server, a proxy that re-signs HTTPS, or an internal CA missing from `cacerts`.

## Quick fix

A one-certificate chain means fixing the server; a full chain to an unknown root means importing that root.

Decide whether the server or the JVM is wrong before importing anything:

```bash
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
```

- Only one certificate in the output and `Verify return code: 21 (unable to verify the first certificate)`: the **server chain is incomplete**. Configure the full chain on the server (see [missing intermediate certificate](https://ssl.sh/errors/missing-intermediate-certificate/)).
- Full chain, but the top `issuer` is your company, a proxy vendor or an internal CA: **the JVM does not trust that root**. Import it into the truststore of the JVM that fails:

```bash
# JDK 9 and later
keytool -importcert -cacerts -alias company-root -file company-root.pem -storepass changeit -noprompt
# JDK 8
keytool -importcert -keystore "$JAVA_HOME/jre/lib/security/cacerts" -alias company-root -file company-root.pem -storepass changeit -noprompt
```

Restart the application afterwards; the truststore is read once at startup.

## Causes

### 1. The server does not send its intermediate certificate

Java never downloads missing intermediates on its own, so a chain that works in Chrome can fail in Java.

- **Confirm:** `openssl s_client -showcerts` shows only the leaf certificate, or the [chain builder](https://ssl.sh/tools/chain-builder/) reports a missing intermediate.
- **Fix:** serve leaf plus intermediates (`fullchain.pem` in Nginx, the full chain file in Apache, Tomcat or your load balancer).

### 2. A TLS-inspecting proxy or security gateway

Corporate proxies decrypt HTTPS and present certificates signed by a private root. Browsers trust it because IT pushed the root into the OS store; Java does not read the OS store.

- **Confirm:** run with `-Djavax.net.debug=ssl:handshake` or check `openssl s_client` from the same machine; the issuer names the proxy product or your company.
- **Fix:** import the proxy root into cacerts, or on Windows use `-Djavax.net.ssl.trustStoreType=Windows-ROOT`.

### 3. Internal CA or self-signed certificate

Internal APIs, Nexus or GitLab instances often use an internal CA.

- **Fix:** import the internal root (not the leaf) once per JVM or, better, build a dedicated truststore and point the application at it:

```bash
keytool -importcert -keystore app-truststore.p12 -storetype PKCS12 -storepass changeit -alias company-root -file company-root.pem -noprompt
java -Djavax.net.ssl.trustStore=app-truststore.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar
```

`javax.net.ssl.trustStore` **replaces** cacerts, so a custom truststore must also contain the public roots your app needs.

### 4. An old JDK with an outdated cacerts

Old JDK builds lack newer roots, so certificates from a CA that switched to a newer root fail.

- **Fix:** update to a current JDK release of your major version; each update ships a refreshed cacerts.

### 5. The app loads a different truststore than you think

Frameworks and servers can set their own truststore (Tomcat connectors, Spring configuration, Kafka or Elasticsearch clients).

- **Confirm:** `-Djavax.net.debug=ssl:trustmanager` prints which truststore was loaded and which certificates it contains.

## Fixes by environment

Add the root to the truststore the JVM loads; on most Linux distributions that means the system store.

**Debian / Ubuntu OpenJDK:** cacerts is generated from the system store by `ca-certificates-java`, so adding the root system-wide also updates Java:

```bash
sudo cp company-root.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
```

**RHEL / Rocky / Fedora:** copy the root to `/etc/pki/ca-trust/source/anchors/` and run `sudo update-ca-trust`; the system OpenJDK reads `/etc/pki/ca-trust/extracted/java/cacerts`.

**Docker images:** bake the root into the image so every container starts with it:

```dockerfile
COPY company-root.pem /tmp/company-root.pem
RUN keytool -importcert -cacerts -alias company-root -file /tmp/company-root.pem -storepass changeit -noprompt
```

**Windows:** use `Windows-ROOT` as above, or run `keytool` from an elevated prompt, because cacerts under `Program Files` is write-protected.

**Build tools:** Maven and Gradle show the same error when downloading dependencies; see [Maven PKIX path building failed](https://ssl.sh/errors/maven-pkix-path-building-failed/).

## Don't do this

- **A trust-all `X509TrustManager`** (empty `checkServerTrusted`) or a `HostnameVerifier` that returns `true`. Copied from forum answers, these turn off authentication completely, and they tend to survive into production.
- **Importing the leaf certificate** instead of the root. It hides the real problem and breaks again at the next renewal.
- **Deleting or replacing cacerts** with a file from another machine or an old JDK. You lose current roots and any later JDK update overwrites your change.
