apache/beam · error · IOException

Can't load the client certificate from the keystore

Error message

Can't load the client certificate from the keystore

What it means

ConnectionConfiguration.getSSLContext() builds an SSLContext from a provided keystore to secure TLS connections to Elasticsearch. Any exception while loading the keystore file or the trust material (bad password, corrupt/malformed file, unreadable path) is rethrown as an IOException with this message, wrapping the underlying cause.

Solutions

  1. Check the wrapped cause in the exception for the exact keystore failure reason
  2. Verify keystorePath points to an existing, readable keystore file
  3. Confirm keystorePassword matches the keystore's actual password
  4. Validate the keystore with `keytool -list -keystore <path>` before deploying
  5. Ensure the keystore format matches KeyStore.getDefaultType() (JKS vs PKCS12)

Example fix

// before
ConnectionConfiguration.create("es-host", 9200)
    .setKeystorePath("/secrets/keystore.jks").setKeystorePassword(null);
// after
ConnectionConfiguration.create("es-host", 9200)
    .setKeystorePath("/secrets/keystore.jks").setKeystorePassword(keystorePassword);
Defensive patterns

Strategy: validation

Validate before calling

File ks = new File(keystorePath);
if (!ks.isFile() || !ks.canRead())
  throw new IllegalArgumentException("Keystore missing/unreadable: " + keystorePath);
try (InputStream in = new FileInputStream(ks)) {
  KeyStore.getInstance("PKCS12").load(in, password.toCharArray()); // throws if bad
}

Try / catch

try {
  pipeline.apply(ElasticsearchIO.read().withConnectionConfiguration(cc));
} catch (IllegalArgumentException | IOException e) {
  throw new IllegalStateException("ES TLS setup failed: " + e.getCause(), e);
}

Prevention

When it happens

Trigger: ConnectionConfiguration.setKeystorePath(...)/setKeystorePassword(...) set to a nonexistent, corrupt, or password-protected keystore; wrong keystore password; keystore bytes not loadable as a KeyStore.

Common situations: Typo in keystore path in deployment config; keystore regenerated with a different password; secret mounted empty in Kubernetes; JKS vs PKCS12 format mismatch.

Understand the failure class

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/dc173899c3d1647b. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/io/elasticsearch/src/main/java/org/apache/beam/sdk/io/elasticsearch/ElasticsearchIO.java:708

      builder.addIfNotNull(DisplayData.item("socketTimeout", getSocketTimeout()));
      builder.addIfNotNull(DisplayData.item("connectTimeout", getConnectTimeout()));
      builder.addIfNotNull(DisplayData.item("trustSelfSignedCerts", isTrustSelfSignedCerts()));
      builder.addIfNotNull(DisplayData.item("compressionEnabled", isCompressionEnabled()));
    }

    private SSLContext getSSLContext() throws IOException {
      if (getKeystorePath() != null && !getKeystorePath().isEmpty()) {
        try {
          KeyStore keyStore = KeyStore.getInstance("jks");
          try (InputStream is = new FileInputStream(new File(getKeystorePath()))) {
            String keystorePassword = getKeystorePassword();
            keyStore.load(is, (keystorePassword == null) ? null : keystorePassword.toCharArray());
          }
          final TrustStrategy trustStrategy =
              isTrustSelfSignedCerts() ? new TrustSelfSignedStrategy() : null;
          return SSLContexts.custom().loadTrustMaterial(keyStore, trustStrategy).build();
        } catch (Exception e) {
          throw new IOException("Can't load the client certificate from the keystore", e);
        }
      }
      return null;
    }

    @VisibleForTesting
    RestClient createClient() throws IOException {
      HttpHost[] hosts = new HttpHost[getAddresses().size()];
      int i = 0;
      for (String address : getAddresses()) {
        URL url = new URL(address);
        hosts[i] = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
        i++;
      }
      RestClientBuilder restClientBuilder = RestClient.builder(hosts);
      if (getPathPrefix() != null) {
        restClientBuilder.setPathPrefix(getPathPrefix());
      }

View on GitHub (pinned to 12126d8942)