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

  1. Remove the keyStore*/trustStore* fields from the config when format is PEM (or vice versa — drop trustCertsFilePath/certificateFilePath/keyFilePath when format is KEYSTORE)
  2. Set tlsFormat/PolicyFormat to KEYSTORE if the actual material is .jks/.p12 stores, or PEM if the material is .crt/.key/.pem files
  3. Audit merged configuration layers so only one TLS material style is populated
  4. 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

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

Related errors


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