keycloak/keycloak · error · RuntimeException

Failed to load truststore

Error message

Failed to load truststore

What it means

Thrown from HttpClientBuilder.build(AdapterHttpClientConfig) when adapterConfig.getTruststore() is set but KeystoreUtil.loadKeyStore(truststorePath, truststorePassword) throws — file missing, wrong type, wrong password, or unreadable. The path is first run through EnvUtil.replace (so ${env} placeholders are expanded). It becomes a RuntimeException("Failed to load truststore", e) with the cause.

Source

Thrown at adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientBuilder.java:349

            }
            return client;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public HttpClient build(AdapterHttpClientConfig adapterConfig) {
        disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing

        String truststorePath = adapterConfig.getTruststore();
        if (truststorePath != null) {
            truststorePath = EnvUtil.replace(truststorePath);
            String truststorePassword = adapterConfig.getTruststorePassword();
            try {
                this.truststore = KeystoreUtil.loadKeyStore(truststorePath, truststorePassword);
            } catch (Exception e) {
                throw new RuntimeException("Failed to load truststore", e);
            }
        }
        String clientKeystore = adapterConfig.getClientKeystore();
        if (clientKeystore != null) {
            clientKeystore = EnvUtil.replace(clientKeystore);
            String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
            try {
                KeyStore clientCertKeystore = KeystoreUtil.loadKeyStore(clientKeystore, clientKeystorePassword);
                keyStore(clientCertKeystore, clientKeystorePassword);
            } catch (Exception e) {
                throw new RuntimeException("Failed to load keystore", e);
            }
        }

        HttpClientBuilder.HostnameVerificationPolicy policy = HttpClientBuilder.HostnameVerificationPolicy.WILDCARD;
        if (adapterConfig.isAllowAnyHostname())
            policy = HttpClientBuilder.HostnameVerificationPolicy.ANY;
        connectionPoolSize(adapterConfig.getConnectionPoolSize());

View on GitHub (pinned to 66c7e15a37)

Solutions

  1. Inspect RuntimeException.getCause() for the precise keystore error (FileNotFoundException vs IOException vs CertificateException).
  2. Confirm the absolute path the adapter sees after EnvUtil.replace (resolve ${env} vars and expand relative paths).
  3. Verify the password matches and the file is the expected keystore type.
  4. Ensure the file is readable by the adapter process/container user.

Example fix

<!-- before: path missing / wrong password -->
<truststore>file:${jboss.server.config.dir}/trust.jks</truststore>
<truststorePassword>old-password</truststorePassword>
<!-- after: absolute path exists and password is correct -->
<truststore>/opt/keycloak/conf/trust.jks</truststore>
<truststorePassword>correct-password</truststorePassword>
Defensive patterns

Strategy: validation

Validate before calling

String path = EnvUtil.replace(adapterConfig.getTruststore());
File f = new File(path);
if (adapterConfig.getTruststore() != null && (!f.isFile() || !f.canRead())) {
    throw new IllegalStateException("Truststore not readable: " + f.getAbsolutePath());
}
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream is = new FileInputStream(f)) {
    ks.load(is, adapterConfig.getTruststorePassword().toCharArray()); // throws on wrong password
}

Try / catch

try {
    HttpClient client = new HttpClientBuilder().build(adapterConfig);
} catch (RuntimeException e) {
    if (e.getMessage().equals("Failed to load truststore")) logger.error("Bad truststore config", e.getCause());
    throw e;
}

Prevention

When it happens

Trigger: Configuring <truststore>/<truststorePassword> (or equivalent AdapterHttpClientConfig) where the file path resolves (after env substitution) to a missing/unreadable file, the type is unsupported, or the password is wrong.

Common situations: Relative path resolved against an unexpected working directory; ${env} variable not set so the literal placeholder is used; truststore password mismatch; truststore in PKCS12 but expected JKS (or vice-versa); file permission issue in a container.

Related errors


AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14). Data as JSON: /api/errors/7e8450df6b0b0328. Report an issue: GitHub.