apache/seatunnel · error · RuntimeException

Unexpected default trust managers:

Error message

Unexpected default trust managers:

What it means

SSLUtils.createSSLContext initializes the default TrustManagerFactory from the configured trust store and expects it to yield exactly one TrustManager that is an X509TrustManager. If the JDK/security provider returns a different set (multiple managers or a non-X509 type), this RuntimeException is thrown because the code cannot build the SSLContext it needs for HTTPS connections to Elasticsearch.

Source

Thrown at seatunnel-connectors-v2/connector-elasticsearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/elasticsearch/util/SSLUtils.java:111

            keyManagers = keyManagerFactory.getKeyManagers();
        }

        // load TrustStore if configured, otherwise use KeyStore
        KeyStore trustStore = keyStore;
        if (trustStorePath.isPresent()) {
            File trustStoreFile = new File(trustStorePath.get());
            trustStore = loadTrustStore(trustStoreFile, trustStorePassword);
        }

        // create TrustManagerFactory
        TrustManagerFactory trustManagerFactory =
                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);

        // get X509TrustManager
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new RuntimeException(
                    "Unexpected default trust managers:" + Arrays.toString(trustManagers));
        }
        // create SSLContext
        SSLContext result = SSLContext.getInstance("SSL");
        result.init(keyManagers, trustManagers, null);
        return result;
    }

    private static KeyStore loadTrustStore(File trustStorePath, Optional<String> trustStorePassword)
            throws IOException, GeneralSecurityException {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try {
            // attempt to read the trust store as a PEM file
            List<X509Certificate> certificateChain = PemReader.readCertificateChain(trustStorePath);
            if (!certificateChain.isEmpty()) {
                trustStore.load(null, null);
                for (X509Certificate certificate : certificateChain) {
                    X500Principal principal = certificate.getSubjectX500Principal();

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Run on a standard Oracle/OpenJDK/Temurin JDK with the default SUN security provider, where the default algorithm yields a single X509TrustManager.
  2. Check java.security (securerandom/source and ssl.TrustManagerFactoryAlgorithm overrides) and remove custom TrustManagerFactory algorithm overrides.
  3. If a FIPS or IBM JDK is required, supply a custom trust manager wrapper that picks the X509TrustManager from the array instead of relying on this utility.
  4. Inspect the exception's Arrays.toString(trustManagers) output to identify which provider returned the unexpected managers.

Example fix

// before (JDK with multiple trust managers)
SSLContext ctx = SSLUtils.buildSSLContext(trustStore, keyStore, password);
// after (pick the X509TrustManager explicitly in a custom utility)
X509TrustManager x509 = (X509TrustManager) Arrays.stream(trustManagerFactory.getTrustManagers())
        .filter(tm -> tm instanceof X509TrustManager).findFirst()
        .orElseThrow(() -> new RuntimeException("No X509TrustManager found"));
sslContext.init(keyManagers, new TrustManager[]{x509}, null);
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the default trust managers before building the SSL context
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
for (TrustManager tm : tmf.getTrustManagers()) {
    if (!(tm instanceof X509TrustManager)) {
        throw new IllegalStateException("Provider returns non-X509 trust managers: " + tm);
    }
}

Type guard

boolean hasSingleX509TrustManager(TrustManager[] tms) {
    return tms != null && tms.length == 1 && tms[0] instanceof X509TrustManager;
}

Try / catch

try {
    SSLContext ctx = SSLUtils.buildSSLContext(trustStore, keyStore, password);
} catch (RuntimeException e) {
    if (e.getMessage().startsWith("Unexpected default trust managers")) {
        log.error("JDK/security provider returned unsupported TrustManagers; switch to a standard JDK", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling buildSSLContext when trustManagerFactory.getTrustManagers() returns an array with length != 1 or whose first element is not an X509TrustManager. Happens with unusual JCE security providers, custom crypto setups (e.g. IBM JDK, FIPS providers), or exotic trust store configurations.

Common situations: Running on a JDK or security provider (FIPS-enabled JVM, IBM JDK, custom java.security file) that registers multiple trust managers; corrupt or non-standard trust store entries; exotic SSL configurations in containerized environments.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/e34a46140c6141f3. Report an issue: GitHub.