apache/pulsar · error · RuntimeException

Key reader class does not have constructor accepts map

Error message

Key reader class does not have constructor accepts map

What it means

After the CryptoKeyReader class is loaded, CryptoUtils requires a public constructor accepting a single Map (of configs) to instantiate it. If the class has no Map-argument constructor (NoSuchMethodException), this RuntimeException with cause is thrown. This is an SPI convention: crypto key reader implementations must expose CryptoKeyReader(Map<String,Object> configs).

Source

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

        return bldr.build();
    }

    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) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Add a public constructor taking Map<String,Object> (raw Map parameter per getConstructor(Map.class)) to your CryptoKeyReader implementation
  2. If the class cannot be changed, wrap it in an adapter class with the required Map constructor
  3. Confirm the constructor is public and takes exactly one java.util.Map parameter (not a subtype or Object)

Example fix

// before
class MyKeyReader implements CryptoKeyReader {
    public MyKeyReader() { }
    ...
}
// after
class MyKeyReader implements CryptoKeyReader {
    public MyKeyReader(Map<String, Object> configs) {
        // initialize from configs
    }
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = ClassLoaderUtils.loadClass(className, classLoader);
boolean hasMapCtor = false;
for (Constructor<?> ctor : c.getConstructors()) {
    if (ctor.getParameterCount() == 1 && ctor.getParameterTypes()[0] == Map.class) { hasMapCtor = true; }
}
if (!hasMapCtor) throw new IllegalStateException(className + " needs a public Map-arg constructor");

Try / catch

try {
    CryptoKeyReader reader = CryptoUtils.getCryptoKeyReaderInstance(className, configs, classLoader);
} catch (RuntimeException e) {
    if (e.getMessage().contains("constructor accepts map")) { /* add CryptoKeyReader(Map) constructor */ }
}

Prevention

When it happens

Trigger: A custom CryptoKeyReader class exists on the classpath but only defines a no-arg constructor (or default constructor only), while getCryptoKeyReaderInstance calls cryptoClass.getConstructor(Map.class).

Common situations: implementations written against older examples using a no-arg constructor; refactoring that removed the Map constructor; implementing CryptoKeyReader in Kotlin/Scala without generating the Map-arg constructor.

Related errors


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