apache/pulsar · critical · IllegalStateException
Failed to acquire TLS material for purpose ${purpose}
Error message
Failed to acquire TLS material for purpose ${purpose} What it means
JettyTlsFactory.awaitAcquisition blocks until TLS key/certificate material (the native Jetty SslContextFactory) has been resolved for a given 'purpose'. If the asynchronous acquisition completes exceptionally, RuntimeExceptions/Errors are rethrown as-is; anything else is wrapped in this IllegalStateException. It means the broker could not obtain or build its TLS context (bad keystore, unreadable key file, failed decryption), so TLS listeners cannot start.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/jetty/tls/JettyTlsFactory.java:472
* so a configuration failure surfaces as its own cause. The underlying messages ("No TLS material
* configured for server purpose WEB") are the actionable ones and should not arrive wrapped.
*
* @param pending the acquisition
* @param purpose the purpose being acquired, for the failure message
* @return the acquisition result
*/
private static <T> T awaitAcquisition(CompletableFuture<T> pending, TlsPurpose purpose) {
try {
return pending.join();
} catch (CompletionException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
if (cause instanceof RuntimeException runtime) {
throw runtime;
}
if (cause instanceof Error error) {
throw error;
}
throw new IllegalStateException("Failed to acquire TLS material for purpose " + purpose, cause);
}
}
/**
* Overlay a factory-supplied engine baseline onto a synthesized server factory (PIP-478 merge order):
* enabled protocols/cipher suites when the companion sets them, and the companion's client-auth mode as
* authoritative (rule 4) — {@code needClientAuth} wins over {@code wantClientAuth}, neither means none.
*/
private static void applyServerBaseline(SslContextFactory.Server sslContextFactory, SSLParameters baseline) {
if (baseline.getProtocols() != null) {
sslContextFactory.setIncludeProtocols(baseline.getProtocols());
}
if (baseline.getCipherSuites() != null) {
sslContextFactory.setIncludeCipherSuites(baseline.getCipherSuites());
}
if (baseline.getNeedClientAuth()) {
sslContextFactory.setNeedClientAuth(true);
} else if (baseline.getWantClientAuth()) {View on GitHub (pinned to 820761864e)
Solutions
- Inspect the 'cause' of the IllegalStateException — it names the real TLS failure (bad password, missing file, invalid keystore).
- Verify the keystore/certificate and key file paths exist and are readable by the broker process user.
- Confirm the keystore password and type (JKS/PKCS12) match the actual file; for PEM, check tlsKeyFilePath/tlsCertificateFilePath/tlsTrustCertsFilePath values.
- Validate the certificate/key pair and chain (openssl x509 / keytool -list) and renew if expired.
- Ensure the TLS provider configuration (e.g. OpenSSL vs JDK provider) is consistent with the supplied material.
Example fix
// before (broker.conf) tlsCertificateFilePath=/missing/cert.pem tlsKeyFilePath=/missing/key.pem // after tlsCertificateFilePath=/etc/pulsar/tls/broker.cert.pem tlsKeyFilePath=/etc/pulsar/tls/broker.key.pem # chmod 600 /etc/pulsar/tls/broker.key.pem
Defensive patterns
Strategy: validation
Validate before calling
// Validate TLS material before broker startup
java.nio.file.Path cert = java.nio.file.Path.of(conf.getTlsCertificateFilePath());
java.nio.file.Path key = java.nio.file.Path.of(conf.getTlsKeyFilePath());
if (!java.nio.file.Files.isReadable(cert)) throw new IllegalStateException("Unreadable cert: " + cert);
if (!java.nio.file.Files.isReadable(key)) throw new IllegalStateException("Unreadable key: " + key);
if (conf.getTlsKeyStorePassword() != null) {
try (var in = java.nio.file.Files.newInputStream(java.nio.file.Path.of(conf.getTlsKeyStore()))) {
var ks = java.security.KeyStore.getInstance("PKCS12");
ks.load(in, conf.getTlsKeyStorePassword().toCharArray());
} catch (Exception e) {
throw new IllegalStateException("Keystore cannot be loaded: " + e.getMessage(), e);
}
} Try / catch
try {
factory.acquireNativeJettyFactory(purpose).get();
} catch (java.util.concurrent.ExecutionException e) {
throw new IllegalStateException("TLS material invalid for purpose " + purpose + ": " + e.getCause(), e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} Prevention
- Verify cert/key paths and file permissions (readable by the broker user, key mode 600) before start.
- Confirm keystore passwords and store types match the actual files.
- Monitor certificate expiry and renew ahead of time.
- Keep PEM/JKS provider config consistent; run keytool -list or openssl checks in deploy pipelines.
- Always log the cause chain — the IllegalStateException wraps the real TLS error.
When it happens
Trigger: Calling acquireNativeJettyFactory / subscription / resolveBaselineParameters when the underlying acquisition future failed with a non-RuntimeException cause: KeyStore load failure, UnrecoverableKeyException, FileNotFoundException on the keystore/truststore path, wrong key-store password, or unsupported certificate format.
Common situations: Misconfigured tlsCertificateFilePath/tlsKeyFilePath or keystore paths in broker.conf; wrong keystore password; expired/invalid certificates; file permissions preventing the broker user from reading the TLS material; switching TLS providers (PEM vs JKS/PKCS12) without matching config.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Cross-format TLS material: tlsPolicy(...) configures a keyst
- Cross-format TLS material: tlsPolicy(...) configures a PEM t
- The replication cluster does not provide TLS encrypted servi
- No usable service URL (useTls=${useTls}, serviceUrl=${servic
- Passed in parameter empty. KEYSTORE_PATH: ${keyStorePath} KE
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/c432e51e33c577b0.
Report an issue: GitHub.