apache/pulsar · error · IllegalStateException
Client TLS factory <factory.getClass().getName()> supplied…
Error message
Client TLS factory <factory.getClass().getName()> supplied no Netty SslContext for purpose <purpose>
What it means
probe() validates a PulsarTlsFactory by asking it to produce a Netty SslContext for a given TlsPurpose (client/server connection) via TlsContextAcquisition. If the future completes with an empty Optional, the factory failed to supply a context for that purpose, and an IllegalStateException is thrown naming the factory class and purpose. This signals the factory implementation does not support or did not configure that purpose.
Solutions
- Implement the missing purpose in your PulsarTlsFactory so acquireNettyContext returns a valid SslContext handle.
- Supply the required key/cert/truststore config so the factory can synthesize the context.
- Check TlsContextAcquisition logs for why the acquisition completed empty (async failure swallowed).
- Update the custom factory for the current Pulsar TlsPurpose enum / synthesis spec API.
Example fix
// before (custom factory) Optional<TlsHandle<SslContext>> h = purpose == TlsPurpose.CLIENT ? build() : Optional.empty(); // after Optional<TlsHandle<SslContext>> h = buildFor(purpose, synthesis); // build for every purpose
Defensive patterns
Strategy: validation
Validate before calling
boolean supportsPurpose(PulsarTlsFactory f, TlsPurpose p) {
try {
var h = TlsContextAcquisition.acquireNettyContext(f, p, spec).get(5, TimeUnit.SECONDS);
boolean ok = h.isPresent(); h.ifPresent(TlsHandle::dispose);
return ok;
} catch (Exception e) { return false; }
} Try / catch
try {
ClientTlsFactorySupport.probe(factory, purpose, spec);
} catch (IllegalStateException e) {
if (e.getMessage().contains("supplied no Netty SslContext")) {
log.error("Factory lacks support/keys for purpose " + purpose, e);
}
} Prevention
- Implement all TlsPurpose cases in custom factories
- Load key/cert material before registration so context creation cannot be skipped
- Add a startup smoke test that probes each purpose
- Log inside acquireNettyContext to surface swallowed async failures
When it happens
Trigger: resolveClientTlsFactory probing a custom PulsarTlsFactory whose acquireNettyContext returns empty for a purpose (e.g. factory only implements client auth context but probe requests server-purpose synthesis, or keys/certs missing so the factory yields no context).
Common situations: Custom TLS factory that returns Optional.empty for unsupported purposes; missing key/cert material so context creation is skipped; purpose/purpose-specific synthesis spec mismatch after a Pulsar upgrade adding new purposes.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- No TLS context available (factory not initialized or closed)
- bindAddresses: ip:port
- cert/key file path or cert/key stream must be present
- certFilePath must not be null
- Certificate loading error
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/b1dbc223abd7add2.
Report an issue: GitHub.
Appendix: source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/tls/ClientTlsFactorySupport.java:620
.build();
}
/**
* Fail-fast probe: build one instance of the purpose and dispose it, surfacing a configuration error
* (e.g. a missing cert file) as an actionable {@link IllegalArgumentException}. Acquisition goes through
* {@link TlsContextAcquisition}, so a custom factory that supplies only the JDK {@code SSLContext}
* fallback probes successfully via the framework-synthesized Netty context.
*
* @param factory the initialized factory
* @param purpose the purpose to probe
* @param synthesis the settings baked into a synthesized Netty context on the fallback path
*/
public static void probe(PulsarTlsFactory factory, TlsPurpose purpose, TlsSynthesisSpec synthesis) {
try {
Optional<TlsHandle<SslContext>> handle =
TlsContextAcquisition.acquireNettyContext(factory, purpose, synthesis).get();
if (handle.isEmpty()) {
throw new IllegalStateException("Client TLS factory " + factory.getClass().getName()
+ " supplied no Netty SslContext for purpose " + purpose);
}
handle.get().dispose();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while probing the client TLS factory", e);
} catch (ExecutionException | CompletionException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
throw new IllegalArgumentException("Client TLS configuration is invalid for purpose " + purpose
+ ": " + cause.getMessage(), cause);
}
}
private static void initializeBlocking(PulsarTlsFactory factory, TlsFactoryInitContext context)
throws Exception {
try {
factory.initialize(context).get();
} catch (ExecutionException e) {View on GitHub (pinned to 820761864e)