{"record":{"id":"bece69645361a0de","repo":"prestodb/presto","slug":"expected-exactly-one-x509trustmanager-but-found","errorCode":null,"errorMessage":"Expected exactly one X509TrustManager, but found: ${trustManagers}","messagePattern":"Expected exactly one X509TrustManager, but found: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClientFactory.java","lineNumber":152,"sourceCode":"                final KeyManagerFactory metastoreKeyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n                metastoreKeyManagerFactory.init(metastoreKeyStore, keyManagerPassword);\n                metastoreKeyManagers = metastoreKeyManagerFactory.getKeyManagers();\n            }\n\n            // load TrustStore if configured, otherwise use KeyStore\n            KeyStore metastoreTrustStore = metastoreKeyStore;\n            if (truststorePath.isPresent()) {\n                metastoreTrustStore = getTrustStore(truststorePath.get(), trustStorePassword);\n            }\n\n            // create TrustManagerFactory\n            final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n            trustManagerFactory.init(metastoreTrustStore);\n\n            // get X509TrustManager\n            final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();\n            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {\n                throw new RuntimeException(\"Expected exactly one X509TrustManager, but found:\" + Arrays.toString(trustManagers));\n            }\n\n            // create SSLContext\n            final SSLContext sslContext = SSLContext.getInstance(PROTOCOL);\n            sslContext.init(metastoreKeyManagers, trustManagers, null);\n            return Optional.of(sslContext);\n        }\n        catch (GeneralSecurityException | IOException e) {\n            throw new PrestoException(HIVE_METASTORE_INITIALIZE_SSL_ERROR, e);\n        }\n    }\n\n    /**\n     * Reads the truststore certificate and returns it\n     *\n     * @param trustStorePath\n     * @param trustStorePassword\n     * @throws IOException","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClientFactory.java#L134-L170","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use a truststore containing only trusted CA certificates (keytool -import -trustcacerts), not a keystore with keys.","Verify the truststore loads and contains entries: keytool -list -v -keystore truststore.jks.","Set the store type explicitly to match the file (e.g. -Dhive.metastore.thrift.ssl.truststore.type=JKS/PKCS12).","Remove non-standard security providers from java.security or run on a standard JDK.","If a custom TrustManagerFactory is required, ensure it returns exactly one X509TrustManager."],"exampleFix":"// before\n# truststore is actually a keystore with private keys\nhive.metastore.thrift.ssl.truststore=/etc/hive/server.keystore\n// after\nkeytool -importcert -alias corporate-ca -file corp-ca.pem -keystore truststore.jks\nhive.metastore.thrift.ssl.truststore=/etc/hive/truststore.jks","handlingStrategy":"validation","validationCode":"// validate truststore before enabling metastore SSL\nKeyStore ts = KeyStore.getInstance(\"JKS\");\ntry (InputStream in = Files.newInputStream(Paths.get(truststorePath))) {\n    ts.load(in, truststorePassword);\n}\nint certs = Collections.list(ts.aliases()).size();\nif (certs != 1) {\n    throw new IllegalStateException(\"truststore must contain exactly one CA cert, found \" + certs);\n}","typeGuard":null,"tryCatchPattern":"try {\n    HiveMetastoreClient client = clientFactory.create(...);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Expected exactly one X509TrustManager\")) {\n        // fix truststore contents/type, then retry\n    } else {\n        throw e;\n    }\n}","preventionTips":["Keep a dedicated truststore holding only CA certs, separate from identity keystores","Validate store contents with keytool -list after every rotation","Pin the JVM's security providers; avoid exotic JCE providers on Presto nodes","Match store type flags (JKS/PKCS12) to the actual file format","Add truststore load checks to deployment smoke tests"],"tags":["ssl","tls","truststore","hive-metastore"],"backgroundTag":"trustmanager-configuration","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}