quarkusio/quarkus · error · RuntimeException

Failed to load keystore

Error message

Failed to load keystore

What it means

Thrown during HttpClientBuilder.build() when the client keystore configured for mutual TLS (client certificate authentication) cannot be loaded via KeystoreUtil.loadKeyStore. This is the client-certificate counterpart of the truststore failure and aborts HTTP client construction.

Source

Thrown at extensions/keycloak-authorization/runtime/src/main/java/io/quarkus/keycloak/pep/runtime/HttpClientBuilder.java:438

        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());
        hostnameVerification(policy);
        if (adapterConfig.isDisableTrustManager()) {
            disableTrustManager();
        } else {
            trustStore(truststore);
        }

        configureProxyForAuthServerIfProvided(adapterConfig);

        if (socketTimeout == -1 && adapterConfig.getSocketTimeout() > 0) {
            socketTimeout(adapterConfig.getSocketTimeout(), TimeUnit.MILLISECONDS);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify the client keystore path resolves correctly at runtime (remember EnvUtil environment substitution) and the file is present/readable.
  2. Confirm client-keystore-password matches the keystore's store password.
  3. Recreate the keystore in a supported format: keytool -genkeypair -keystore client.p12 -storetype PKCS12 and align config (store type).
  4. If mTLS is not required, remove the client-keystore configuration entirely.

Example fix

// before (wrong password / path)
quarkus.oidc.tls.key-store-file=/etc/certs/client.jks
quarkus.oidc.tls.key-store-password=oldpass
// after
quarkus.oidc.tls.key-store-file=/etc/certs/client.p12
quarkus.oidc.tls.key-store-password=currentpass
quarkus.oidc.tls.key-store-file-type=PKCS12
Defensive patterns

Strategy: validation

Validate before calling

File ksFile = new File(clientKeystorePath);
if (!ksFile.isFile() || !ksFile.canRead())
    throw new IllegalStateException("Client keystore missing/unreadable: " + ksFile.getAbsolutePath());
KeyStore ks = KeyStore.getInstance("PKCS12");
try (InputStream in = new FileInputStream(ksFile)) { ks.load(in, clientKeystorePassword.toCharArray()); }

Try / catch

try {
    client = HttpClientBuilder.create(adapterConfig).build();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Failed to load keystore")) {
        log.error("Check client keystore path/password/type: {}", adapterConfig.getClientKeystore(), e.getCause());
    }
    throw e;
}

Prevention

When it happens

Trigger: AdapterConfig defines a client keystore (quarkus.oidc.tls.key-store-file / adapterConfig.getClientKeystore()) but the file path is wrong, the client-keystore password is wrong, the format/type is unsupported, or the file is unreadable in the runtime environment.

Common situations: Mounting the keystore in Kubernetes but pointing config at the host path; PKCS12 vs JKS store type mismatch; password containing special characters mangled by env substitution; keystore regenerated with a new password after rotation.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/0a7e490e3308f49f. Report an issue: GitHub.