apache/pulsar · error · IllegalArgumentException

The input serialization/deserialization class %s does not ex

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.

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)

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.