apache/pulsar · error · IllegalArgumentException
Serializer type mismatch ${typeArg} vs ${serDeTypeArg}
Error message
Serializer type mismatch ${typeArg} vs ${serDeTypeArg} What it means
Thrown by ValidatorUtils.validateSerde in the serialization (deser=false) branch when the SerDe's declared type parameter is not a supertype of the function's output type argument. For serialization, the SerDe must be able to accept the function's output type, i.e. serDeTypeArg.asErasure().isAssignableFrom(typeArg.asErasure()) must hold.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/ValidatorUtils.java:168
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 "
+ serDeTypeArg.getActualName());
}
}
}
private static void validateSchemaType(TypeDefinition schema, TypeDefinition typeArg, TypePool typePool,
boolean input) {
TypeDescription.Generic schemaTypeArg = schema.getInterfaces().stream()
.filter(i -> i.asErasure().isAssignableTo(Schema.class))
.findFirst()
.map(i -> i.getTypeArguments().get(0))
.orElse(null);
if (input) {
if (!schemaTypeArg.asErasure().isAssignableTo(typeArg.asErasure())) {
throw new IllegalArgumentException(
"Schema type mismatch " + typeArg.getActualName() + " vs " + schemaTypeArg.getActualName());View on GitHub (pinned to 820761864e)
Solutions
- Set the function's output type argument to a type assignable to the SerDe's type parameter.
- Update the SerDe to implement SerDe<ActualOutputType> (or a supertype of the actual output).
- Point the output serializer config at a SerDe written for the current output type.
Example fix
// before
public class OutSerde implements SerDe<LegacyOut> { ... }
public class MyFunction implements Function<In, NewOut> { ... }
// after
public class OutSerde implements SerDe<NewOut> { ... } Defensive patterns
Strategy: type-guard
Validate before calling
static boolean serdeMatchesOutput(String serdeClass, Class<?> outputType, ClassLoader cl) {
try {
for (Type t : Class.forName(serdeClass, false, cl).getGenericInterfaces()) {
if (t instanceof ParameterizedType
&& ((ParameterizedType) t).getRawType() == SerDe.class) {
Type arg = ((ParameterizedType) t).getActualTypeArguments()[0];
return arg instanceof Class<?> && outputType.isAssignableFrom((Class<?>) arg) == false
? outputType.equals(arg) || ((Class<?>) arg).isAssignableFrom(outputType)
: true;
}
}
return false;
} catch (ClassNotFoundException e) { return false; }
} Type guard
static boolean isSerDeAccepting(Class<?> serdeElementType, Class<?> outputType) {
return serdeElementType.isAssignableFrom(outputType);
} Try / catch
try {
validateSerde(outputSerializer, typeArg, typePool, false);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Serializer type mismatch")) {
throw new IllegalStateException("Output SerDe " + outputSerializer
+ " cannot serialize function output type; update its generic parameter", e);
}
throw e;
} Prevention
- Keep the output SerDe's type parameter a supertype of (or equal to) the function's declared output type.
- Update output SerDe config whenever the function's output type changes.
- Do not copy input SerDe settings into output serializer fields.
When it happens
Trigger: validateSerde(inputSerializer, typeArg, typePool, false) where the SerDe implements SerDe<T> and typeArg is not assignable to T — e.g. the function outputs SubEvent but the output SerDe is SerDe<UnrelatedType>; or a SerDe typed to a sibling class that the output does not extend.
Common situations: Output type changed in a function refactor while the output SerDe config was left pointing at the old type's SerDe; using a base-class SerDe where the function emits an unrelated type; copy-pasting input SerDe settings into the output SerDe field.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Serializer type mismatch
- Inconsistent types found between function input type and tim
- Sink transform function output must be of type Record
- The input serialization/deserialization class %s does not ex
- Schema type mismatch ${typeArg} vs ${schemaTypeArg}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/140fda1ee9d5ec6f.
Report an issue: GitHub.