apache/pulsar · error · IllegalArgumentException

The input serialization/deserialization class

Error message

The input serialization/deserialization class %s does not exist

What it means

Thrown by ValidatorUtils.validateSerde when the configured serialization/deserialization class name cannot be resolved from the TypePool — i.e. the named class is not on the classpath visible to the validator (TypePool.Resolution.NoSuchTypeException). The validator inspects function config at submission time, before the function is deployed.

Solutions

  1. Verify the fully-qualified class name in the function config matches the SerDe class exactly (package + class).
  2. Make sure the class is contained in the function jar/Archive you submit — the TypePool resolves against the submitted artifacts.
  3. Rebuild/redeploy the function package after renaming the SerDe class so the config points at the new name.
  4. If you don't need a custom SerDe, clear the field so validateSerde short-circuits (empty string or DefaultSerDe is allowed).

Example fix

// before (class renamed, config stale)
--inputs-serde com.example.serde.OldEventSerde
// after
--inputs-serde com.example.serde.EventSerde  (class repackaged in the function jar)
Defensive patterns

Strategy: validation

Validate before calling

static boolean serdeExists(String serdeClass, ClassLoader cl) {
    if (serdeClass == null || serdeClass.isEmpty()
            || "org.apache.pulsar.functions.api.utils.DefaultSerDe".equals(serdeClass)) return true;
    try { Class.forName(serdeClass, false, cl); return true; }
    catch (ClassNotFoundException e) { return false; }
}

Try / catch

try {
    validateSerde(inputSerializer, typeArg, typePool, deser);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("does not exist")) {
        throw new IllegalStateException("SerDe class not on classpath: " + inputSerializer
            + " — check the FQCN and that it is packaged in the function jar", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling validateSerde(inputSerializer, typeArg, typePool, deser) with a non-empty inputSerializer that is not the DefaultSerDe and for which typePool.describe(inputSerializer) throws NoSuchTypeException: wrong fully-qualified class name, class not in the jar searched by the TypePool, or a typo in the package.

Common situations: Typing the SerDe class name by hand in function config (typos, wrong package); forgetting to shade the SerDe class into the function's uber jar; renaming or moving the SerDe class during a refactor while old tenant/namespace configs still reference the old name; relying on a class that exists on the broker but not in the submitted function archive.

Related errors


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

Appendix: source

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

            throw new IllegalArgumentException(
                    String.format("The message payload processor class %s does not implement the desired constructor.",
                            conf.getClassName()));
        }
    }

    public static void validateSerde(String inputSerializer, TypeDefinition typeArg, TypePool typePool,
                                     boolean deser) {
        if (isEmpty(inputSerializer)) {
            return;
        }
        if (inputSerializer.equals(DEFAULT_SERDE)) {
            return;
        }
        TypeDescription serdeClass;
        try {
            serdeClass = typePool.describe(inputSerializer).resolve();
        } catch (TypePool.Resolution.NoSuchTypeException e) {
            throw new IllegalArgumentException(
                    String.format("The input serialization/deserialization class %s does not exist",
                            inputSerializer));
        }
        TypeDescription.Generic serDeTypeArg = serdeClass.getInterfaces().stream()
                .filter(i -> i.asErasure().isAssignableTo(SerDe.class))
                .findFirst()
                .map(i -> i.getTypeArguments().get(0))
                .orElseThrow(() -> new IllegalArgumentException(
                        String.format("%s does not implement %s", inputSerializer, SerDe.class.getName())));

        if (deser) {
            if (!serDeTypeArg.asErasure().isAssignableTo(typeArg.asErasure())) {
                throw new IllegalArgumentException("Serializer type mismatch " + typeArg.getActualName() + " vs "
                        + serDeTypeArg.getActualName());
            }
        } else {
            if (!serDeTypeArg.asErasure().isAssignableFrom(typeArg.asErasure())) {
                throw new IllegalArgumentException("Serializer type mismatch " + typeArg.getActualName() + " vs "

View on GitHub (pinned to 820761864e)