apache/pulsar · error · IllegalArgumentException
privateKeyProvider must be set when failureAction is FAIL
Error message
privateKeyProvider must be set when failureAction is FAIL
What it means
ConsumerEncryptionPolicy enforces that a PrivateKeyProvider is supplied when the crypto failure action is ConsumerCryptoFailureAction.FAIL. With FAIL, the consumer must be able to decrypt messages and will fail consumption on any decryption error; without a key provider it could never decrypt anything, so the constructor throws IllegalArgumentException rather than allowing a configuration that always fails.
Source
Thrown at pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/ConsumerEncryptionPolicy.java:48
* <p>Construct via {@link #builder()}. The {@link PrivateKeyProvider} is required
* when {@link #failureAction()} is {@link ConsumerCryptoFailureAction#FAIL} (the
* default — strict mode); for {@link ConsumerCryptoFailureAction#DISCARD} or
* {@link ConsumerCryptoFailureAction#CONSUME} the provider may be omitted, in
* which case the consumer just relies on the failure action to decide what to do
* with encrypted messages it can't decrypt.
*/
@EqualsAndHashCode
@ToString
public final class ConsumerEncryptionPolicy {
private final PrivateKeyProvider privateKeyProvider;
private final ConsumerCryptoFailureAction failureAction;
private ConsumerEncryptionPolicy(PrivateKeyProvider privateKeyProvider,
ConsumerCryptoFailureAction failureAction) {
Objects.requireNonNull(failureAction, "failureAction must not be null");
if (failureAction == ConsumerCryptoFailureAction.FAIL && privateKeyProvider == null) {
throw new IllegalArgumentException(
"privateKeyProvider must be set when failureAction is FAIL");
}
this.privateKeyProvider = privateKeyProvider;
this.failureAction = failureAction;
}
/**
* @return the provider used to load private keys for decryption, or {@code null}
* when the consumer doesn't decrypt and falls back to the failure action
* (DISCARD or CONSUME)
*/
public PrivateKeyProvider privateKeyProvider() {
return privateKeyProvider;
}
/**
* @return the action the consumer takes when decryption fails
*/View on GitHub (pinned to 820761864e)
Solutions
- Provide a key provider: .privateKeyProvider(...) / .keyProvider(...) with a working implementation before building.
- If you don't have keys, use ConsumerCryptoFailureAction.CONSUME or DISCARD instead of FAIL.
- Ensure the key source (KMS credentials, key file path, env vars) is actually available at client startup.
Example fix
// before
ConsumerEncryptionPolicy p = ConsumerEncryptionPolicy.builder()
.failureAction(ConsumerCryptoFailureAction.FAIL) // IllegalArgumentException: no key provider
.build();
// after
ConsumerEncryptionPolicy p = ConsumerEncryptionPolicy.builder()
.privateKeyProvider(new DefaultKeyProvider())
.failureAction(ConsumerCryptoFailureAction.FAIL)
.build(); Defensive patterns
Strategy: validation
Validate before calling
if (action == ConsumerCryptoFailureAction.FAIL && keyProvider == null) {
throw new IllegalStateException("A privateKeyProvider is required when failureAction is FAIL");
}
ConsumerEncryptionPolicy p = ConsumerEncryptionPolicy.builder()
.privateKeyProvider(keyProvider)
.failureAction(action)
.build(); Type guard
static boolean isFailConfigValid(ConsumerCryptoFailureAction a, PrivateKeyProvider p) {
return a != ConsumerCryptoFailureAction.FAIL || p != null;
} Try / catch
try {
policy = ConsumerEncryptionPolicy.builder()
.failureAction(ConsumerCryptoFailureAction.FAIL)
.privateKeyProvider(provider)
.build();
} catch (IllegalArgumentException e) {
log.error("FAIL action requires a key provider; check encryption config", e);
throw e;
} Prevention
- Whenever you set failureAction to FAIL, configure a key provider in the same builder chain.
- Verify KMS credentials / key files are present at client startup, not at first encrypted message.
- If keys are unavailable, deliberately choose CONSUME or DISCARD instead of FAIL.
When it happens
Trigger: Calling ConsumerEncryptionPolicy with failureAction = FAIL and privateKeyProvider = null, e.g. ConsumerEncryptionPolicy.builder().failureAction(ConsumerCryptoFailureAction.FAIL).build() without a keyProvider(...); or wiring FAIL dynamically from config where the provider was never configured.
Common situations: Tightening the failure action from CONSUME/DISCARD to FAIL for security without also adding the key provider; a key management service or env-based key config missing at startup; environment promotion (dev without encryption keys to prod with encrypted topics).
Related errors
- configuredService should not be an instance of SystemTopicBa
- The ${alg.name()} algorithm does not support Key Pairs.
- SHA-256 algorithm not found
- The shared resource doesn't support thread pool configurati
- No resources have been configured while using shareConfigure
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/454217a778878e60.
Report an issue: GitHub.