prestodb/presto · error · RuntimeException

Expected exactly one X509TrustManager, but found: ${trustMan

Error message

Expected exactly one X509TrustManager, but found: ${trustManagers}

What it means

When building the TLS context for a secured metastore connection, the factory initializes a TrustManagerFactory from the configured truststore and requires exactly one X509TrustManager. If the truststore yields zero or multiple trust managers, or a non-X509 one, the JDK default algorithm produced something unexpected, so a RuntimeException is thrown rather than proceeding with ambiguous trust settings.

Source

Thrown at presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClientFactory.java:152

                final KeyManagerFactory metastoreKeyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                metastoreKeyManagerFactory.init(metastoreKeyStore, keyManagerPassword);
                metastoreKeyManagers = metastoreKeyManagerFactory.getKeyManagers();
            }

            // load TrustStore if configured, otherwise use KeyStore
            KeyStore metastoreTrustStore = metastoreKeyStore;
            if (truststorePath.isPresent()) {
                metastoreTrustStore = getTrustStore(truststorePath.get(), trustStorePassword);
            }

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

            // get X509TrustManager
            final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new RuntimeException("Expected exactly one X509TrustManager, but found:" + Arrays.toString(trustManagers));
            }

            // create SSLContext
            final SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
            sslContext.init(metastoreKeyManagers, trustManagers, null);
            return Optional.of(sslContext);
        }
        catch (GeneralSecurityException | IOException e) {
            throw new PrestoException(HIVE_METASTORE_INITIALIZE_SSL_ERROR, e);
        }
    }

    /**
     * Reads the truststore certificate and returns it
     *
     * @param trustStorePath
     * @param trustStorePassword
     * @throws IOException

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Use a truststore containing only trusted CA certificates (keytool -import -trustcacerts), not a keystore with keys.
  2. Verify the truststore loads and contains entries: keytool -list -v -keystore truststore.jks.
  3. Set the store type explicitly to match the file (e.g. -Dhive.metastore.thrift.ssl.truststore.type=JKS/PKCS12).
  4. Remove non-standard security providers from java.security or run on a standard JDK.
  5. If a custom TrustManagerFactory is required, ensure it returns exactly one X509TrustManager.

Example fix

// before
# truststore is actually a keystore with private keys
hive.metastore.thrift.ssl.truststore=/etc/hive/server.keystore
// after
keytool -importcert -alias corporate-ca -file corp-ca.pem -keystore truststore.jks
hive.metastore.thrift.ssl.truststore=/etc/hive/truststore.jks
Defensive patterns

Strategy: validation

Validate before calling

// validate truststore before enabling metastore SSL
KeyStore ts = KeyStore.getInstance("JKS");
try (InputStream in = Files.newInputStream(Paths.get(truststorePath))) {
    ts.load(in, truststorePassword);
}
int certs = Collections.list(ts.aliases()).size();
if (certs != 1) {
    throw new IllegalStateException("truststore must contain exactly one CA cert, found " + certs);
}

Try / catch

try {
    HiveMetastoreClient client = clientFactory.create(...);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Expected exactly one X509TrustManager")) {
        // fix truststore contents/type, then retry
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: hive.metastore.thrift.ssl.truststore configured with a store containing multiple/zero certificate entries, or a JVM/provider whose default TrustManagerFactory returns several TrustManagers (e.g. unusual security providers or a truststore of an unsupported type).

Common situations: Using a keystore (.jks with private keys) as the truststore by mistake; truststore file corrupt or empty; custom JCE providers installed; mixing PKCS12/JKS types; vendor JVMs with multiple trust managers.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/bece69645361a0de. Report an issue: GitHub.