apache/pulsar · error · RuntimeException
Failed to load crypto key reader class %sx
Error message
Failed to load crypto key reader class %sx
What it means
CryptoUtils.getCryptoKeyReaderInstance loads a CryptoKeyReader implementation class by name using the provided classloader and instantiates it. If ClassLoaderUtils.loadClass cannot find the class (ClassNotFoundException), it throws this RuntimeException — note the message appends a stray 'x' after the class name ('...class com.foo.MyReaderx').
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/CryptoUtils.java:97
keyNames.add(spec.getProducerEncryptionKeyNameAt(i));
}
bldr.cryptoKeyReaderClassName(spec.getCryptoKeyReaderClassName())
.cryptoKeyReaderConfig(cryptoReaderConfig)
.consumerCryptoFailureAction(getConsumerCryptoFailureAction(spec.getConsumerCryptoFailureAction()))
.producerCryptoFailureAction(getProducerCryptoFailureAction(spec.getProducerCryptoFailureAction()))
.encryptionKeys(keyNames.toArray(new String[0]));
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:View on GitHub (pinned to 820761864e)
Solutions
- Correct the fully-qualified class name in the crypto config (also verify no trailing whitespace/newline)
- Add the jar containing the CryptoKeyReader implementation to the classpath (client -cp, connector's extra deps directory, or fat jar)
- Verify the class implements org.apache.pulsar.client.api.CryptoKeyReader and is public
Example fix
// before
Map<String,String> m = new HashMap<>();
m.put("cryptoKeyReaderClassName", "com.example.MyCryptoReader"); // class not in jar
// after
m.put("cryptoKeyReaderClassName", "com.example.crypto.MyCryptoKeyReader");
// and: add target/my-crypto-impl.jar to the connector's extra deps or client classpath Defensive patterns
Strategy: try-catch
Validate before calling
try {
Class.forName(cryptoKeyReaderClassName, true, classLoader);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("CryptoKeyReader class not on classpath: " + cryptoKeyReaderClassName);
} Try / catch
try {
CryptoKeyReader reader = CryptoUtils.getCryptoKeyReaderInstance(className, configs, classLoader);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Failed to load crypto key reader class")) { /* fix class name / add jar */ }
} Prevention
- Verify the FQCN with Class.forName or javap before configuring it
- Ensure the crypto implementation jar ships in the connector's extra-deps or client classpath
- Grep the deployment bundle for the class file to confirm packaging
When it happens
Trigger: Producer/Consumer/Reader crypto config specifies cryptoKeyReaderClassName for a class not on the classpath of the client/connector, e.g. a typo in the fully-qualified name, or the jar containing the implementation was never added to the client's/worker's classpath.
Common situations: fat-jar for a Pulsar IO connector not including the custom CryptoKeyReader class; class name changed after refactoring/upgrade; running the client with a shaded classloader where the crypto class lives in a different jar.
Related errors
- Key reader class does not have constructor accepts map
- Error creating client for HealthChecker
- Entry filter `${name}` cannot be loaded, see the broker logs
- Failed to decode private key
- Failed to decode public key
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/b9291b6b70eb3e85.
Report an issue: GitHub.