apache/pulsar · error · IllegalArgumentException

Missing encryption key name for producer crypto key reader

Error message

Missing encryption key name for producer crypto key reader

What it means

When a crypto key reader is configured on the producer side (isProducer == true), encryptionKeys must list at least one public key name used to encrypt the message. validateCryptoKeyReader throws this IllegalArgumentException when getEncryptionKeys() is null or empty.

Solutions

  1. Set encryptionKeys in the producer conf (or pass --encryption-key) with the key names available from the key reader
  2. If encryption is not intended, remove the cryptoKeyReaderClassName instead of leaving crypto half-configured

Example fix

// before
// producerConf: { "cryptoKeyReaderClassName": "com.acme.MyKeyReader" } // no encryptionKeys
// after
// producerConf: { "cryptoKeyReaderClassName": "com.acme.MyKeyReader", "encryptionKeys": ["my-public-key"] }
Defensive patterns

Strategy: validation

Validate before calling

if (isProducer && (conf.getEncryptionKeys() == null || conf.getEncryptionKeys().length == 0)) {
    throw new IllegalStateException("Producer crypto requires encryptionKeys to be set");
}

Try / catch

try {
    ValidatorUtils.validateCryptoKeyReader(conf, typePool, true);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Missing encryption key name")) {
        // set encryptionKeys in producer conf or drop the crypto config
    }
    throw e;
}

Prevention

When it happens

Trigger: Setting cryptoKeyReaderClassName in a source function's producer conf without setting encryptionKeys, or setting encryptionKeys to an empty array, while isProducer is true.

Common situations: Copying a consumer-side crypto config into a source function; forgetting the --encryption-key CLI flag; clearing encryption keys after switching to encrypted topics.

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


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

Appendix: source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/ValidatorUtils.java:99

                    String.format("The crypto key reader class %s does not exist", cryptoClassName));
        }
        if (!cryptoClass.asErasure().isAssignableTo(CryptoKeyReader.class)) {
            throw new IllegalArgumentException(
                    String.format("%s does not implement %s", cryptoClassName, CryptoKeyReader.class.getName()));
        }

        boolean hasConstructor = cryptoClass.getDeclaredMethods().stream()
                .anyMatch(method -> method.isConstructor() && method.getParameters().size() == 1
                        && method.getParameters().get(0).getType().asErasure().represents(Map.class));

        if (!hasConstructor) {
            throw new IllegalArgumentException(
                    String.format("The crypto key reader class %s does not implement the desired constructor.",
                            conf.getCryptoKeyReaderClassName()));
        }

        if (isProducer && (conf.getEncryptionKeys() == null || conf.getEncryptionKeys().length == 0)) {
            throw new IllegalArgumentException("Missing encryption key name for producer crypto key reader");
        }
    }

    public static void validateMessagePayloadProcessor(MessagePayloadProcessorConfig conf, TypePool typePool) {
        if (isEmpty(conf.getClassName())) {
            return;
        }

        String payloadProcessorClassName = conf.getClassName();
        TypeDescription payloadProcessorClass = null;
        try {
            payloadProcessorClass = typePool.describe(payloadProcessorClassName).resolve();
        } catch (TypePool.Resolution.NoSuchTypeException e) {
            throw new IllegalArgumentException(
                    String.format("The message payload processor class %s does not exist", payloadProcessorClassName));
        }
        if (!payloadProcessorClass.asErasure().isAssignableTo(MessagePayloadProcessor.class)) {
            throw new IllegalArgumentException(String.format("%s does not implement %s", payloadProcessorClassName,

View on GitHub (pinned to 820761864e)