apache/pulsar · error · IllegalArgumentException

The message payload processor class %s does not exist

Error message

The message payload processor class %s does not exist

What it means

validateMessagePayloadProcessor resolves conf.getClassName() via a ByteBuddy TypePool; when the named MessagePayloadProcessor class cannot be found on the classpath (NoSuchTypeException) this IllegalArgumentException is thrown. The payload processor handles BatchSource payload decoding (e.g. Avro, Parquet).

Source

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

                            conf.getCryptoKeyReaderClassName()));
        }

        if (isProducer && (conf.getEncryptionKeys() == null || conf.getEncryptionKeys().length == 0)) {
            throw new IllegalArgumentException("Missing encryption key name for producer crypto key reader");
        }
    }

    public static void validateMessagePayloadProcessor(MessagePayloadProcessorConfig conf, TypePool typePool) {
        if (isEmpty(conf.getClassName())) {
            return;
        }

        String payloadProcessorClassName = conf.getClassName();
        TypeDescription payloadProcessorClass = null;
        try {
            payloadProcessorClass = typePool.describe(payloadProcessorClassName).resolve();
        } catch (TypePool.Resolution.NoSuchTypeException e) {
            throw new IllegalArgumentException(
                    String.format("The message payload processor class %s does not exist", payloadProcessorClassName));
        }
        if (!payloadProcessorClass.asErasure().isAssignableTo(MessagePayloadProcessor.class)) {
            throw new IllegalArgumentException(String.format("%s does not implement %s", payloadProcessorClassName,
                    MessagePayloadProcessor.class.getName()));
        }

        boolean hasConstructor;
        if (conf.getConfig() == null || conf.getConfig().isEmpty()) {
            hasConstructor = payloadProcessorClass.getDeclaredMethods().stream()
                    .anyMatch(method -> method.isConstructor() && method.getParameters().size() == 0);
        } else {
            hasConstructor = payloadProcessorClass.getDeclaredMethods().stream()
                    .anyMatch(method -> method.isConstructor() && method.getParameters().size() == 1
                            && method.getParameters().get(0).getType().asErasure().represents(Map.class));
        }

        if (!hasConstructor) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Correct the className in the payload processor config
  2. Package the MessagePayloadProcessor implementation into the submitted jar
  3. Use a processor class confirmed to exist in your Pulsar version (check the org.apache.pulsar.functions.utils.collections / processor packages for your release)

Example fix

// before
// className: com.acme.OldProcessor // removed in this Pulsar version
// after
// className: org.apache.pulsar.functions.avro.AvroPayloadProcessor // exists in classpath
Defensive patterns

Strategy: validation

Validate before calling

try {
    Class.forName(conf.getClassName());
} catch (ClassNotFoundException e) {
    throw new IllegalStateException("Payload processor class missing: " + conf.getClassName());
}

Try / catch

try {
    ValidatorUtils.validateMessagePayloadProcessor(conf, typePool);
} catch (IllegalArgumentException e) {
    if (e.getMessage().endsWith("does not exist")) {
        // correct className or package the processor class
    }
    throw e;
}

Prevention

When it happens

Trigger: Configuring a MessagePayloadProcessorConfig with a className that is missing from the function jar or worker classpath, or a typo in the FQCN.

Common situations: Referencing a built-in processor class (e.g. AvroPayloadProcessor) that is not shipped with the worker version; custom processor jar not uploaded; package renamed across Pulsar releases.

Related errors


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