apache/pulsar · error · KeyStoreException
The pinned provider's TrustManagerFactory returned no…
Error message
The pinned provider's TrustManagerFactory returned no X509TrustManager; trust cannot be established. Managers: trustManagers
What it means
TlsContexts.singleX509TrustManager selects the X509TrustManager from the array produced by a TrustManagerFactory. If the pinned provider's factory yielded no X509TrustManager (empty array or only other TrustManager types), client trust cannot be established and KeyStoreException is thrown listing the managers found.
Solutions
- Switch to the default provider, or verify the pinned provider supports the configured truststore type and X.509 trust management
- Inspect the manager list printed in the message to see what the factory returned
- Check the truststore file is valid, non-empty, and loadable by the provider
- Upgrade or replace the provider; re-enable the default JVM TrustManagerFactory if the pinned one is unnecessary
Example fix
// before builder.trustManager(customProviderTmf); // yields no X509TrustManager // after builder.trustManager(defaultTmf); // standard X509TrustManager
Defensive patterns
Strategy: type-guard
Type guard
static boolean hasX509TrustManager(TrustManagerFactory tmf) {
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) return true;
}
return false;
} Try / catch
try {
TlsContexts.applyTrust(builder, tmf);
} catch (KeyStoreException e) {
log.error("Pinned provider returned no X509TrustManager: {}", e.getMessage());
} Prevention
- Verify the pinned provider supports the configured truststore type before adopting it
- Pre-flight check tmf.getTrustManagers() for an X509TrustManager when using custom providers
- Keep provider versions tested against the JDK in use
When it happens
Trigger: Building a TLS context with a pinned security provider whose TrustManagerFactory.getTrustManagers() returns no X509TrustManager — e.g. a provider that cannot handle the configured truststore type or yields only custom manager types.
Common situations: Non-default pinned security provider incompatible with the truststore type; misconfigured/empty truststore producing zero managers; provider or JDK upgrade changing manager types.
Related errors
- Configured keystore 'keyStorePath' holds no usable key…
- Configured truststore 'trustStorePath' holds no X.509…
- Cross-format TLS material: tlsPolicy(...) configures a…
- Cross-format TLS material: tlsPolicy(...) configures a PEM…
- Failed to acquire TLS material for purpose
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/285aad6919f96a0b.
Report an issue: GitHub.
Appendix: source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/tls/impl/TlsContexts.java:467
TrustManager[] trustManagers = JdkSslContexts.createTrustManagers(material.trustCertsArray(), false,
jsseProvider, jcaProvider);
builder.trustManager(singleX509TrustManager(trustManagers));
}
/**
* Netty's {@code trustManager(TrustManager)} accepts exactly one manager (it wraps it in a
* {@code TrustManagerFactory}), and a {@code TrustManagerFactory} initialized from a keystore returns a
* single {@code X509TrustManager}, so pick that one and fail loudly rather than silently dropping trust if
* a provider ever returns something unexpected.
*/
private static TrustManager singleX509TrustManager(TrustManager[] trustManagers)
throws GeneralSecurityException {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return trustManager;
}
}
throw new KeyStoreException("The pinned provider's TrustManagerFactory returned no X509TrustManager; "
+ "trust cannot be established. Managers: " + Arrays.toString(trustManagers));
}
/**
* Install the client identity on a Netty builder. Keystore material may hold several identities (e.g.
* RSA + EC, or identities issued by different accepted CAs), so the whole set goes to a
* {@link KeyManagerFactory} and JSSE selects one by the peer's requested key type / acceptable issuers.
* PEM material has a single identity (key + chain) and keeps Netty's raw overload unless a provider axis
* is pinned, in which case it too must go through a factory this class builds (see {@link #applyTrust}).
*/
private static void applyKeyManager(SslContextBuilder builder, TlsMaterial material, TlsPolicy policy)
throws Exception {
if (material.hasKeyStoreEntries()) {
builder.keyManager(buildKeyManagerFactory(material, policy));
} else if (material.hasKeyMaterial()) {
KeyManagerFactory pinned = pinnedPemKeyManagerFactory(material, policy);
if (pinned != null) {
builder.keyManager(pinned);View on GitHub (pinned to 820761864e)