apache/pulsar · error · IllegalArgumentException

The crypto key reader class %s does not exist

Error message

The crypto key reader class %s does not exist

What it means

validateCryptoKeyReader resolves conf.getCryptoKeyReaderClassName() through a ByteBuddy TypePool; if the named class cannot be found on the classpath (NoSuchTypeException) it throws this IllegalArgumentException. The crypto key reader supplies keys for end-to-end message encryption.

Source

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

            return SchemaType.valueOf(schemaTypeOrClassName.toUpperCase());
        } catch (IllegalArgumentException e) {
            // schemaType is not referring to builtin type
            return null;
        }
    }


    public static void validateCryptoKeyReader(CryptoConfig conf, TypePool typePool, boolean isProducer) {
        if (isEmpty(conf.getCryptoKeyReaderClassName())) {
            return;
        }

        String cryptoClassName = conf.getCryptoKeyReaderClassName();
        TypeDescription cryptoClass = null;
        try {
            cryptoClass = typePool.describe(cryptoClassName).resolve();
        } catch (TypePool.Resolution.NoSuchTypeException e) {
            throw new IllegalArgumentException(
                    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)) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Fix the FQCN in cryptoKeyReaderClassName
  2. Package the CryptoKeyReader implementation in the submitted function jar
  3. Avoid shade relocation of the crypto class (keep it outside relocation prefixes) so its name stays stable

Example fix

// before
// cryptoKeyReaderClassName: com.acme.shaded.MyKeyReader // relocated name
// after
// cryptoKeyReaderClassName: com.acme.MyKeyReader // original, packaged in jar
Defensive patterns

Strategy: validation

Validate before calling

try {
    Class.forName(cryptoKeyReaderClassName);
} catch (ClassNotFoundException e) {
    throw new IllegalStateException("Crypto key reader not in classpath: " + cryptoKeyReaderClassName);
}

Try / catch

try {
    ValidatorUtils.validateCryptoKeyReader(conf, typePool, isProducer);
} catch (IllegalArgumentException e) {
    if (e.getMessage().endsWith("does not exist")) {
        // fix FQCN or bundle the class, then resubmit
    }
    throw e;
}

Prevention

When it happens

Trigger: Setting CryptoKeyReaderClassName in ProducerConfig/ConsumerConfig (function crypto conf) to a class absent from the function worker classpath, or a misspelled FQCN.

Common situations: Forgot to bundle custom CryptoKeyReader implementation in the function jar; class relocated by shading so the configured name no longer matches; typo when writing the function yaml/CLI flag.

Related errors


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