SonarSource/sonarqube · critical · IllegalStateException

Failed to setup SSL context on ES client

Error message

Failed to setup SSL context on ES client

What it means

EsClient.buildSslContext loads a keystore (trust store) from sonar.auth.elasticsearch... keyStorePath and builds an SSLContext for the Elasticsearch REST client. Any IOException (missing/unreadable file) or GeneralSecurityException (bad password, corrupted keystore, unsupported algorithm) is wrapped in an IllegalStateException, as TLS setup is mandatory for a secured ES connection.

Source

Thrown at server/sonar-server-common/src/main/java/org/sonar/server/es/EsClient.java:344

      clientBuilder.addRequestInterceptorFirst((request, entity, context) -> {
        if (!request.containsHeader("Authorization")) {
          request.addHeader("Authorization", headerValue);
        }
      });
    }
    return clientBuilder.build();
  }

  private static SSLContext buildSslContext(String keyStorePath, @Nullable String keyStorePassword) {
    try {
      KeyStore keyStore = KeyStore.getInstance("pkcs12");
      try (InputStream is = Files.newInputStream(Paths.get(keyStorePath))) {
        keyStore.load(is, keyStorePassword == null ? null : keyStorePassword.toCharArray());
      }
      SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(keyStore, null);
      return sslBuilder.build();
    } catch (IOException | GeneralSecurityException e) {
      throw new IllegalStateException("Failed to setup SSL context on ES client", e);
    }
  }

  <R> R execute(EsRequestExecutor<R> executor) {
    return execute(executor, () -> "");
  }

  <R> R execute(EsRequestExecutor<R> executor, Supplier<String> requestDetails) {
    Profiler profiler = Profiler.createIfTrace(EsClient.LOGGER).start();
    try {
      return executor.execute();
    } catch (Exception e) {
      throw new ElasticsearchException("Fail to execute es request" + requestDetails.get(), e);
    } finally {
      if (profiler.isTraceEnabled()) {
        profiler.stopTrace(requestDetails.get());
      }
    }

View on GitHub (pinned to 184c821202)

Solutions

  1. Verify the keyStorePath exists and is readable by the SonarQube process user (absolute path recommended).
  2. Confirm the keystore password is correct and matches the file.
  3. Validate the keystore with `keytool -list -keystore <file>`; recreate it if corrupted.
  4. Ensure the keystore format is supported (JKS/PKCS12) and consistent with the loader.
  5. Check that the secret/config mount is present in containerized deployments.

Example fix

// before (sonar.properties)
sonar.cluster.es.ssl.keystorePath=es-keystore.jks
// after
sonar.cluster.es.ssl.keystorePath=/opt/sonarqube/conf/es-keystore.p12
Defensive patterns

Strategy: validation

Validate before calling

Path ks = Paths.get(keyStorePath);
if (!Files.isRegularFile(ks) || !Files.isReadable(ks)) {
  throw new IllegalStateException("ES keystore missing or unreadable: " + ks);
}
// additionally verify with:
// keytool -list -keystore es-keystore.p12 -storepass <password>

Try / catch

try {
  EsClient client = esClientFactory.build();
} catch (IllegalStateException e) {
  if ("Failed to setup SSL context on ES client".equals(e.getMessage())) {
    throw new ConfigurationException("Check sonar.cluster.es.ssl.keystorePath/password", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: sonar.cluster.es.ssl.keystorePath (or equivalent) points to a non-existent or unreadable file; wrong keystore password; keystore in an unsupported format/corrupted; missing JCE algorithm.

Common situations: K8s/containers where the keystore secret was not mounted; password mismatch after rotation; PKCS12 vs JKS format confusion; relative paths resolving to the wrong working directory.

Understand the failure class

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/efaaede6afaf56bd. Report an issue: GitHub.