apache/pulsar · error · RuntimeException

Failed to load message payload processor class %sx

Error message

Failed to load message payload processor class %sx

What it means

getMessagePayloadProcessorInstance loads the configured MessagePayloadProcessor class via ClassLoaderUtils.loadClass; on ClassNotFoundException it throws a RuntimeException with this message (note the stray 'x' typo in the format string, e.g. 'com.foo.MyProcessorx'). The 'x' is a formatting artifact, not part of the class name.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/MessagePayloadProcessorUtils.java:41

import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.Map;
import org.apache.pulsar.client.api.MessagePayloadProcessor;
import org.apache.pulsar.common.functions.MessagePayloadProcessorConfig;
import org.apache.pulsar.common.util.ClassLoaderUtils;
import org.apache.pulsar.functions.proto.MessagePayloadProcessorSpec;

public class MessagePayloadProcessorUtils {
    public static MessagePayloadProcessor getMessagePayloadProcessorInstance(String className,
                                                                             Map<String, Object> configs,
                                                                             ClassLoader classLoader) {
        Class<?> payloadProcessorClass;
        try {
            payloadProcessorClass = ClassLoaderUtils.loadClass(className, classLoader);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(
                    String.format("Failed to load message payload processor class %sx", className));
        }

        try {
            if (configs == null || configs.isEmpty()) {
                Constructor<?> ctor = payloadProcessorClass.getConstructor();
                return (MessagePayloadProcessor) ctor.newInstance();
            } else {
                Constructor<?> ctor = payloadProcessorClass.getConstructor(Map.class);
                return (MessagePayloadProcessor) ctor.newInstance(configs);
            }
        } catch (NoSuchMethodException e) {
            if (configs == null || configs.isEmpty()) {
                throw new RuntimeException("Message payload processor class does not have default constructor", e);
            } else {
                throw new RuntimeException("Message payload processor class does not have constructor accepts map", e);
            }
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Correct the className in the function configuration (the 'x' suffix is a bug — the real name is what precedes it)
  2. Package the payload processor class into the function archive
  3. Verify the class exists: 'unzip -l function.jar | grep MessagePayloadProcessor'
  4. Confirm you are loading through the right class loader (function jar vs worker) and that no NAR isolation hides the class

Example fix

// before
"className": "com.mycorp.processors.MyProcesor"  // typo
// after
"className": "com.mycorp.processors.MyProcessor"
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c;
try {
  c = Class.forName(spec.getClassName(), false, functionClassLoader);
  if (!MessagePayloadProcessor.class.isAssignableFrom(c)) {
    throw new IllegalStateException(spec.getClassName() + " is not a MessagePayloadProcessor");
  }
} catch (ClassNotFoundException e) {
  throw new IllegalStateException("Payload processor class not packaged in function archive: " + spec.getClassName());
}

Type guard

boolean isValidPayloadProcessor(String name, ClassLoader cl) {
  try {
    return MessagePayloadProcessor.class.isAssignableFrom(Class.forName(name, false, cl));
  } catch (ClassNotFoundException e) { return false; }
}

Try / catch

try {
  createFunction(...);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Failed to load message payload processor class")) {
    log.error("Processor class not found: {}", spec.getMessagePayloadProcessor().getClassName());
  }
}

Prevention

When it happens

Trigger: Creating/running a function whose messagePayloadProcessor spec contains a className that cannot be resolved through the supplied class loader (function package classloader or worker classloader).

Common situations: Typo in className; processor class not packaged in the function's JAR/NAR; processor built against a different package than deployed; class only present in a NAR while the loader is the jar loader.

Related errors


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