apache/pulsar · error · IllegalArgumentException
TlsPolicy field '${field}' is set but is not valid for forma
Error message
TlsPolicy field '${field}' is set but is not valid for format ${format}; use the fields matching the chosen format (PEM: trustCertsFilePath/certificateFilePath/keyFilePath; KEYSTORE: trustStorePath/keyStorePath/... with keyStoreType/trustStoreType), or set the format to match the material. What it means
TlsPolicy.validateFormatConsistency checks that key material fields match the chosen format: PEM fields (trustCertsFilePath, certificateFilePath, keyFilePath) must be empty when format is KEYSTORE, and KEYSTORE fields (trustStorePath, keyStorePath, keyStoreType, trustStoreType, etc.) must be empty when format is PEM. rejectForFormat throws IllegalArgumentException when a field is populated for the wrong format, preventing a policy that silently ignores or misinterprets TLS material.
Source
Thrown at pulsar-tls-factory-api/src/main/java/org/apache/pulsar/tls/TlsPolicy.java:584
private void validateFormatConsistency() {
if (format == Format.PEM) {
rejectForFormat("trustStorePath", trustStorePath);
rejectForFormat("trustStorePassword", trustStorePassword);
rejectForFormat("keyStorePath", keyStorePath);
rejectForFormat("keyStorePassword", keyStorePassword);
rejectForFormat("keyStoreType", keyStoreType);
rejectForFormat("trustStoreType", trustStoreType);
} else { // Format.KEYSTORE
rejectForFormat("trustCertsFilePath", trustCertsFilePath);
rejectForFormat("certificateFilePath", certificateFilePath);
rejectForFormat("keyFilePath", keyFilePath);
}
}
private void rejectForFormat(String field, String value) {
if (value != null && !value.isBlank()) {
throw new IllegalArgumentException("TlsPolicy field '" + field + "' is set but is not valid for "
+ "format " + format + "; use the fields matching the chosen format (PEM: "
+ "trustCertsFilePath/certificateFilePath/keyFilePath; KEYSTORE: "
+ "trustStorePath/keyStorePath/... with keyStoreType/trustStoreType), or set the format "
+ "to match the material.");
}
}
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Remove the keyStore*/trustStore* fields from the config when format is PEM (or vice versa — drop trustCertsFilePath/certificateFilePath/keyFilePath when format is KEYSTORE)
- Set tlsFormat/PolicyFormat to KEYSTORE if the actual material is .jks/.p12 stores, or PEM if the material is .crt/.key/.pem files
- Audit merged configuration layers so only one TLS material style is populated
- Add a config validation step before deployment that instantiates the TlsPolicy to fail fast on mixed formats
Example fix
// before format=PEM keyStorePath=/path/to/keystore.jks // leftover from KEYSTORE config trustCertsFilePath=/path/to/ca.pem // after format=PEM trustCertsFilePath=/path/to/ca.pem
Defensive patterns
Strategy: validation
Validate before calling
void validateTlsMaterial(String format, String trustCertsFilePath, String certificateFilePath, String keyFilePath,
String trustStorePath, String keyStorePath) {
boolean hasPem = isSet(trustCertsFilePath) || isSet(certificateFilePath) || isSet(keyFilePath);
boolean hasKeystore = isSet(trustStorePath) || isSet(keyStorePath);
if ("PEM".equalsIgnoreCase(format) && hasKeystore) {
throw new IllegalArgumentException("KEYSTORE fields set but format is PEM");
}
if ("KEYSTORE".equalsIgnoreCase(format) && hasPem) {
throw new IllegalArgumentException("PEM fields set but format is KEYSTORE");
}
}
private boolean isSet(String s) { return s != null && !s.isBlank(); } Type guard
boolean isTlsFormatConsistent(String format, boolean pemMaterialSet, boolean keystoreMaterialSet) {
if ("PEM".equalsIgnoreCase(format)) return !keystoreMaterialSet;
if ("KEYSTORE".equalsIgnoreCase(format)) return !pemMaterialSet;
return false;
} Try / catch
try {
TlsPolicy policy = buildTlsPolicy();
policy.validateFormatConsistency(); // or rely on constructor validation
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("TlsPolicy field")) {
LOG.error("TLS material does not match configured format: {}", e.getMessage());
}
throw e;
} Prevention
- Keep only one TLS material style (PEM or KEYSTORE) populated in config, matching the format field
- When migrating between PEM and keystore, delete the obsolete fields rather than leaving them set
- Run a startup-time TlsPolicy validation in CI against production-like config
- Document which fields belong to PEM vs KEYSTORE formats in your deployment templates
When it happens
Trigger: Building a TlsPolicy with format=PEM while any of trustStorePath/keyStorePath/keyStoreType/trustStoreType etc. is set, or format=KEYSTORE while any of trustCertsFilePath/certificateFilePath/keyFilePath is set — the rejectForFormat calls in validateFormatConsistency fire during TlsPolicy construction/build.
Common situations: Migrating from PEM to keystore config and leaving the old PEM paths behind; copy-pasting a TLS config template that includes both styles; an operator adding keyStoreType for 'documentation' while still using PEM files; tools merging two config layers that each set different TLS styles.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Passed in parameter empty. KEYSTORE_PATH: ${keyStorePath} KE
- You must specify tls-trust-store-type, tls-trust-store and t
- 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/035738cf44337352.
Report an issue: GitHub.