apache/pulsar · error · PulsarClientException.CryptoException
Keyname or KeyReader is null
Error message
Keyname or KeyReader is null
What it means
MessageCryptoBc.addPublicKeyCipher validates its arguments before doing any crypto work: if either the key name or the CryptoKeyReader is null it cannot obtain the encryption key, so it throws PulsarClientException.CryptoException immediately. This is a fail-fast argument check, not a crypto failure.
Source
Thrown at pulsar-client-messagecrypto-bc/src/main/java/org/apache/pulsar/client/impl/crypto/MessageCryptoBc.java:373
*
* @param keyNames List of public keys to encrypt data key
*
* @param keyReader Implementation to read the key values
*
*/
@Override
public void addPublicKeyCipher(Set<String> keyNames, CryptoKeyReader keyReader) throws CryptoException {
// Rotate the encryption key each time this method is called
encryptionKey = generateEncryptionKey();
for (String key : keyNames) {
addPublicKeyCipher(key, keyReader);
}
}
private void addPublicKeyCipher(String keyName, CryptoKeyReader keyReader) throws CryptoException {
if (keyName == null || keyReader == null) {
throw new PulsarClientException.CryptoException("Keyname or KeyReader is null");
}
// Read the public key and its info using callback
EncryptionKeyInfo keyInfo = keyReader.getPublicKey(keyName, null);
PublicKey pubKey;
try {
pubKey = loadPublicKey(keyInfo.getKey());
} catch (Exception e) {
String msg = logCtx + "Failed to load public key " + keyName + ". " + e.getMessage();
log.error(msg);
throw new PulsarClientException.CryptoException(msg);
}
Cipher dataKeyCipher;
byte[] encryptedKey;
try {View on GitHub (pinned to 820761864e)
Solutions
- Configure a CryptoKeyReader on the builder: .addKeyReader(new DefaultCryptoKeyReader(keyReaderFilePath))
- Pass a non-null key name to addEncryptionKey() and verify it matches a key your reader can serve via getPublicKey
- Validate configuration loading so keyName/keyReaderPath values are actually populated before building the producer
- Null-check these values in your own startup code to fail with a clearer message
Example fix
// before
Producer<byte[]> p = client.newProducer().addEncryptionKey("myapp.key").create(); // no key reader
// after
CryptoKeyReader reader = new DefaultCryptoKeyReader("/path/to/public/key.pem");
Producer<byte[]> p = client.newProducer().addKeyReader(reader).addEncryptionKey("myapp.key").create(); Defensive patterns
Strategy: validation
Validate before calling
if (keyName == null || keyName.isEmpty()) {
throw new IllegalArgumentException("encryption key name must be set");
}
if (keyReader == null) {
throw new IllegalArgumentException("CryptoKeyReader must be configured before enabling encryption");
} Try / catch
try {
producer = client.newProducer().addKeyReader(keyReader).addEncryptionKey(keyName).create();
} catch (PulsarClientException.CryptoException e) {
log.error("Encryption config incomplete: {}", e.getMessage());
} Prevention
- Always call addKeyReader() on the builder whenever addEncryptionKey() is used
- Load key names and reader paths from validated configuration with startup-time null checks
- Fail fast in application bootstrap rather than lazily at publish time
- Keep key names in one constants/config class to avoid uninitialized variables
When it happens
Trigger: Calling producer/reader addEncryptionKey(keyName) (which delegates to addPublicKeyCipher) with a null keyName, or when no CryptoKeyReader has been configured on the client builder so keyReader is null.
Common situations: Forgetting to call .addKeyReader(keyReader) (or the older cryptoKeyReader config) on the ProducerBuilder while enabling end-to-end encryption; a typo in the key name variable that leaves it uninitialized; building configuration programmatically where a required property failed to load and stayed null.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- Unsupported media type or encoding format: ${contentType}
- Invalid key format
- privateKeyProvider must be set when failureAction is FAIL
- pulsarServiceUrl cannot be null
- pulsarWebServiceUrl cannot be null
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/40d8058ed2f9b7f3.
Report an issue: GitHub.