You ran keytool -importcert with the CA-signed .crt your team returned, and the tool stopped with:
keytool error: java.lang.Exception: Failed to establish chain from replyThat message means keytool received a valid-looking certificate file but could not connect it to a trust anchor already stored in the target keystore. The fix is almost always importing missing CA certificates before the server reply — not regenerating the private key.
This guide reproduces the error on Ubuntu, walks through the corrected import order, explains when -trustcacerts helps, and lists related mistakes Tomcat and Spring Boot admins hit. Commands were tested with OpenJDK 25 and a local OpenSSL intermediate CA.
Tested on: Ubuntu 26.04 LTS; OpenJDK 25.0.3; kernel 7.0.0-27-generic.
Prerequisites
Gather these before reproducing the error — you need the same keystore file that produced the CSR:
- Working
keytool— see Install keytool on Ubuntu. - A PKCS12 keystore with a
PrivateKeyEntryalias and matching CSR. - CA certificate files (
root-ca.crt,intermediate-ca.crt) and the signed server reply. - Optional reading: Import root, intermediate, and server certificate chain and keystore vs truststore.
What the error means
When you import a certificate reply onto an existing key entry, keytool tries to build a PKIX chain from the leaf to a trusted certificate already in the keystore (or, with -trustcacerts, in cacerts). The signed .crt can be perfectly valid — the failure is about trust anchors, not key corruption.
If the issuer of your signed server cert is Lab Intermediate CA but that intermediate is not in the keystore, chain building stops:
keytool error: java.lang.Exception: Failed to establish chain from replyThe private key is fine. The keystore simply lacks the parent certificates.
Reproduce the error (missing intermediate)
Start with a keystore that holds only the server key pair — no CA certificates imported yet. That mirrors what happens when a team imports the leaf reply before the intermediate:
mkdir -p ~/keytool-lab/server
cd ~/keytool-lab/server
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 365 \
-dname "CN=app.lab.local, OU=Lab, O=GoLinuxCloud, C=US" \
-ext "SAN=DNS:app.lab.local,IP:127.0.0.1" \
-keystore broken-chain.p12 -storetype PKCS12 -storepass changeit -noprompt
keytool -certreq -alias server -keystore broken-chain.p12 -storetype PKCS12 \
-storepass changeit -file broken.csrbroken.csr must be signed by the intermediate CA that will issue the server certificate.
Sign the CSR with an intermediate CA (files under ~/keytool-lab/ca/ from the CSR guide):
openssl x509 -req -in broken.csr \
-CA ../ca/intermediate-ca.crt -CAkey ../ca/intermediate-ca.key \
-CAcreateserial -out broken-signed.crt -days 365 -sha256serverAuth extensions as shown in Create a CSR with keytool and import a CA-signed certificate.
Import only the server reply — skipping the intermediate CA on purpose:
keytool -importcert -alias server -file broken-signed.crt \
-keystore broken-chain.p12 -storetype PKCS12 -storepass changeit -nopromptThe failure:
keytool error: java.lang.Exception: Failed to establish chain from replykeytool cannot find Lab Intermediate CA in the keystore, so the reply is rejected. keytool -list still shows only the self-signed bootstrap cert on alias server.
Fix — import CA certificates first
Add the root and intermediate as trustedCertEntry aliases before retrying the server import — root first, then intermediate:
keytool -importcert -alias rootca \
-file ../ca/root-ca.crt \
-keystore broken-chain.p12 -storetype PKCS12 -storepass changeit -noprompt
keytool -importcert -alias intermediateca \
-file ../ca/intermediate-ca.crt \
-keystore broken-chain.p12 -storetype PKCS12 -storepass changeit -nopromptEach import should print Certificate was added to keystore. Confirm the keystore now has two CA entries plus the key:
keytool -list -keystore broken-chain.p12 -storetype PKCS12 -storepass changeitKeystore type: PKCS12
Your keystore contains 3 entries
intermediateca, Jul 2, 2026, trustedCertEntry,
rootca, Jul 2, 2026, trustedCertEntry,
server, Jul 2, 2026, PrivateKeyEntry,The intermediate and root are trust anchors; server still holds the self-signed placeholder until you import the signed reply.
Re-import the signed server certificate on the same alias:
keytool -importcert -alias server -file broken-signed.crt \
-keystore broken-chain.p12 -storetype PKCS12 -storepass changeit -nopromptSuccess:
Certificate reply was installed in keystoreThe leaf now chains to intermediateca inside the same PKCS12 file.
Check that the server cert is no longer self-signed:
keytool -list -v -keystore broken-chain.p12 -storetype PKCS12 -storepass changeit -alias server | grep -E "Owner:|Issuer:"Owner: CN=app.lab.local, OU=Lab, O=GoLinuxCloud, C=US
Issuer: CN=Lab Intermediate CA, O=GoLinuxCloud, C=USIssuer Lab Intermediate CA matches the intermediate you imported — not the temporary self-signed bootstrap.
When -trustcacerts helps
keytool already checks trusted certificates in the target keystore when importing a certificate reply. Add -trustcacerts when you also want keytool to consult the JDK cacerts file. This helps for public CAs already trusted by the JDK, but it does not magically create missing private-CA entries.
For internal PKI, import the private root/intermediate certificates into the target keystore first. Use -trustcacerts only as an additional lookup path, not as a replacement for missing CA files.
For public CAs (DigiCert, Let's Encrypt, etc.), roots are often preloaded in cacerts. Retry the leaf import with -trustcacerts when the signing chain should already be trusted by the JDK:
keytool -importcert -trustcacerts \
-alias server -file server-signed.crt \
-keystore server.p12 -storetype PKCS12 -storepass changeit -nopromptA keystore with only the intermediate preloaded can sometimes succeed with -trustcacerts on leaf import when the JDK already trusts the root, because PKIX only needs a path to a trusted anchor present in the store or cacerts.
Other common causes
Beyond a missing intermediate, these patterns produce the same exception:
Wrong import order in scripts
Automating imports as server → intermediate → root fails on the first step. Script CA imports in root → intermediate → server reply order.
Importing into the wrong keystore
Teams sometimes import the reply into a truststore PKCS12 that has no PrivateKeyEntry for the CSR alias. Use the same keystore file that produced the CSR with keytool -certreq.
Partial bundle from the CA
If the CA emailed only the leaf .crt, download the intermediate bundle from their portal or, if the .p7b reply fails or you want to inspect the chain, split it:
openssl pkcs7 -in bundle.p7b -print_certs -out ca-chain.pemIf the .p7b file is DER encoded, add -inform DER.
Import each CA certificate from the PEM before the server reply.
Confusing with public key mismatch
If the error instead says Public keys in reply and keystore don't match, the certificate belongs to a different CSR or alias. Chain errors are about missing issuers, not mismatched keys — see public keys mismatch fix.
Tomcat and Spring Boot symptoms after chain mistakes
Even after keytool import succeeds, the running service can still serve the wrong certificate or an incomplete chain if the app reads a different keystore, the CA reply was incomplete, or the service was not restarted.
| Platform | Misconfiguration | Symptom |
|---|---|---|
| Tomcat | Chain not in keystore | Browser shows missing intermediate |
| Spring Boot | Wrong server.ssl.key-store path |
App starts with self-signed still active |
| Both | Import into JKS while app reads PKCS12 | File not found or wrong entry type |
Restart the service after fixing the keystore, then inspect what the listener actually serves:
openssl s_client -connect 127.0.0.1:8443 -showcerts </dev/null 2>/dev/null | openssl x509 -noout -issuer -subjectIssuer and subject should reflect the CA-signed leaf, not the temporary self-signed bootstrap. Use the keytool cheat sheet for -list -v and -exportcert during verification.
Troubleshooting checklist
When the error persists after importing CAs, verify these items in order:
| Check | Command |
|---|---|
| Entries present | keytool -list -keystore store.p12 -storepass PASS |
| Intermediate issuer | keytool -list -v -alias intermediateca ... |
| Leaf issuer matches intermediate subject | openssl x509 -in server-signed.crt -noout -issuer |
| CSR alias matches import alias | keytool -list -alias server ... |
| Same keystore as CSR | Compare paths in shell history |
References
Summary
Failed to establish chain from reply means keytool cannot find the intermediate or root CA that signed your server certificate inside the target keystore. Import CA files as trustedCertEntry aliases in root → intermediate → server order, then run keytool -importcert on the PrivateKeyEntry alias again. Use -trustcacerts when anchors already live in cacerts as an extra lookup path. The error is about missing issuers, not a bad private key.

