{"record":{"id":"454217a778878e60","repo":"apache/pulsar","slug":"privatekeyprovider-must-be-set-when-failureaction","errorCode":null,"errorMessage":"privateKeyProvider must be set when failureAction is FAIL","messagePattern":"privateKeyProvider must be set when failureAction is FAIL","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/ConsumerEncryptionPolicy.java","lineNumber":48,"sourceCode":" * <p>Construct via {@link #builder()}. The {@link PrivateKeyProvider} is required\n * when {@link #failureAction()} is {@link ConsumerCryptoFailureAction#FAIL} (the\n * default — strict mode); for {@link ConsumerCryptoFailureAction#DISCARD} or\n * {@link ConsumerCryptoFailureAction#CONSUME} the provider may be omitted, in\n * which case the consumer just relies on the failure action to decide what to do\n * with encrypted messages it can't decrypt.\n */\n@EqualsAndHashCode\n@ToString\npublic final class ConsumerEncryptionPolicy {\n\n    private final PrivateKeyProvider privateKeyProvider;\n    private final ConsumerCryptoFailureAction failureAction;\n\n    private ConsumerEncryptionPolicy(PrivateKeyProvider privateKeyProvider,\n                                     ConsumerCryptoFailureAction failureAction) {\n        Objects.requireNonNull(failureAction, \"failureAction must not be null\");\n        if (failureAction == ConsumerCryptoFailureAction.FAIL && privateKeyProvider == null) {\n            throw new IllegalArgumentException(\n                    \"privateKeyProvider must be set when failureAction is FAIL\");\n        }\n        this.privateKeyProvider = privateKeyProvider;\n        this.failureAction = failureAction;\n    }\n\n    /**\n     * @return the provider used to load private keys for decryption, or {@code null}\n     *         when the consumer doesn't decrypt and falls back to the failure action\n     *         (DISCARD or CONSUME)\n     */\n    public PrivateKeyProvider privateKeyProvider() {\n        return privateKeyProvider;\n    }\n\n    /**\n     * @return the action the consumer takes when decryption fails\n     */","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/ConsumerEncryptionPolicy.java#L30-L66","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nConsumerEncryptionPolicy p = ConsumerEncryptionPolicy.builder()\n    .failureAction(ConsumerCryptoFailureAction.FAIL) // IllegalArgumentException: no key provider\n    .build();\n\n// after\nConsumerEncryptionPolicy p = ConsumerEncryptionPolicy.builder()\n    .privateKeyProvider(new DefaultKeyProvider())\n    .failureAction(ConsumerCryptoFailureAction.FAIL)\n    .build();","handlingStrategy":"validation","validationCode":"if (action == ConsumerCryptoFailureAction.FAIL && keyProvider == null) {\n    throw new IllegalStateException(\"A privateKeyProvider is required when failureAction is FAIL\");\n}\nConsumerEncryptionPolicy p = ConsumerEncryptionPolicy.builder()\n    .privateKeyProvider(keyProvider)\n    .failureAction(action)\n    .build();","typeGuard":"static boolean isFailConfigValid(ConsumerCryptoFailureAction a, PrivateKeyProvider p) {\n    return a != ConsumerCryptoFailureAction.FAIL || p != null;\n}","tryCatchPattern":"try {\n    policy = ConsumerEncryptionPolicy.builder()\n        .failureAction(ConsumerCryptoFailureAction.FAIL)\n        .privateKeyProvider(provider)\n        .build();\n} catch (IllegalArgumentException e) {\n    log.error(\"FAIL action requires a key provider; check encryption config\", e);\n    throw e;\n}","preventionTips":["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."],"tags":["java","configuration","encryption","crypto","illegal-argument"],"backgroundTag":"missing-required-dependency","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}