apache/pulsar · error · IllegalStateException

Client TLS factory <factory.getClass().getName()> supplied n

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.

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)

Solutions

  1. Implement the missing purpose in your PulsarTlsFactory so acquireNettyContext returns a valid SslContext handle.
  2. Supply the required key/cert/truststore config so the factory can synthesize the context.
  3. Check TlsContextAcquisition logs for why the acquisition completed empty (async failure swallowed).
  4. 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

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

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/b1dbc223abd7add2. Report an issue: GitHub.