apache/pulsar · error · KeyStoreException
The pinned provider's TrustManagerFactory returned no X509Tr
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.
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)
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
- Failed to acquire TLS material for purpose ${purpose}
- Passed in parameter empty. KEYSTORE_PATH: ${keyStorePath} KE
- Cross-format TLS material: tlsPolicy(...) configures a keyst
- Cross-format TLS material: tlsPolicy(...) configures a PEM t
- Configured keystore 'keyStorePath' holds no usable key entry
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/285aad6919f96a0b.
Report an issue: GitHub.