apache/pulsar · error · RuntimeException

Failed to create instance for key reader class

Error message

Failed to create instance for key reader class

What it means

CryptoUtils.getCryptoKeyReaderInstance reflectively instantiates a user-provided CryptoKeyReader class using its (java.util.Map) constructor. This error means the constructor exists (otherwise a NoSuchMethodException would be thrown) but invoking it failed — either the class is abstract/an interface and cannot be instantiated, the constructor threw an exception, or the class/constructor is not accessible. It wraps the underlying reflective failure in a RuntimeException.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/CryptoUtils.java:107

    }

    public static CryptoKeyReader getCryptoKeyReaderInstance(String className, Map<String, Object> configs,
                                                             ClassLoader classLoader) {
        Class<?> cryptoClass;
        try {
            cryptoClass = ClassLoaderUtils.loadClass(className, classLoader);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(
                    String.format("Failed to load crypto key reader class %sx", className));
        }

        try {
            Constructor<?> ctor = cryptoClass.getConstructor(Map.class);
            return (CryptoKeyReader) ctor.newInstance(configs);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Key reader class does not have constructor accepts map", e);
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
            throw new RuntimeException("Failed to create instance for key reader class", e);
        }
    }

    public static ProducerCryptoFailureAction getProducerCryptoFailureAction(CryptoSpec.FailureAction action) {
        switch (action) {
            case FAIL:
                return ProducerCryptoFailureAction.FAIL;
            case SEND:
                return ProducerCryptoFailureAction.SEND;
            default:
                throw new RuntimeException(
                        "Unknown producer protobuf failure action " + action.name());
        }
    }

    public static ConsumerCryptoFailureAction getConsumerCryptoFailureAction(CryptoSpec.FailureAction action) {
        switch (action) {
            case FAIL:

View on GitHub (pinned to 820761864e)

Solutions

  1. Fix the user-supplied CryptoKeyReader implementation: make it a public, concrete (non-abstract) class with a public constructor accepting java.util.Map
  2. Inspect the wrapped cause (getCause() of this RuntimeException — often InvocationTargetException) and fix whatever made the constructor throw (e.g. missing/invalid entries in the configs map, unreachable key service)
  3. Ensure the class is on the function worker's classpath and the configured class name matches the deployed artifact version
  4. Log configs keys and verify required parameters before constructing the reader

Example fix

// before
public class MyKeyReader implements CryptoKeyReader {
    MyKeyReader(Map<String, String> configs) { ... } // package-private
}
// after
public class MyKeyReader implements CryptoKeyReader {
    public MyKeyReader(Map<String, String> configs) { ... } // public, no-throw setup
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(className);
if (c.isInterface() || Modifier.isAbstract(c.getModifiers()))
    throw new IllegalArgumentException(className + " is not instantiable");
if (!CryptoKeyReader.class.isAssignableFrom(c))
    throw new IllegalArgumentException(className + " does not implement CryptoKeyReader");
try {
    Constructor<?> ctor = c.getConstructor(Map.class);
    if (!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(c.getModifiers()))
        throw new IllegalArgumentException(className + " or its Map constructor is not public");
} catch (NoSuchMethodException e) {
    throw new IllegalArgumentException(className + " lacks a public (Map) constructor");
}
// also pre-check any required keys your reader expects: configs.containsKey("keyPath")

Try / catch

try {
    CryptoKeyReader reader = CryptoUtils.getCryptoKeyReaderInstance(cls, configs);
} catch (RuntimeException e) {
    Throwable cause = e.getCause();
    if (cause instanceof InvocationTargetException)
        log.error("Key reader constructor threw", cause.getCause());
    else if (cause instanceof InstantiationException)
        log.error("Class is abstract/interface", cause);
    else
        log.error("Inaccessible class/constructor", cause);
    throw new IllegalArgumentException("Invalid CryptoKeyReader class: " + cls.getName(), e);
}

Prevention

When it happens

Trigger: Calling getCryptoKeyReaderInstance(class, configs) with: an abstract class or interface implementing CryptoKeyReader (InstantiationException); a constructor that throws on the supplied configs map (InvocationTargetException); a non-public class/constructor without setAccessible (IllegalAccessException).

Common situations: Misconfigured function/crypto config pointing at the wrong class name or a class from an old artifact version; a key reader whose constructor throws because a required key/certificate path in configs is missing or unreadable (KMS/credentials unavailable); a package-private CryptoKeyReader implementation that isn't exported.

Related errors


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