apache/pulsar · error · IllegalArgumentException
Output Serde mismatch
Error message
Output Serde mismatch
What it means
The output serialization class of a function is immutable on update. If the new config supplies a non-empty outputSerdeClassName that differs from the existing one, validateUpdate rejects the update, since changing the output serializer would break the declared output schema of the existing subscription.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:1056
.isRegexPattern(false)
.build());
});
}
if (!newConfig.getInputSpecs().isEmpty()) {
newConfig.getInputSpecs().forEach((topicName, consumerConfig) -> {
if (!existingConfig.getInputSpecs().containsKey(topicName)) {
throw new IllegalArgumentException("Input Topics cannot be altered");
}
if (consumerConfig.isRegexPattern() != existingConfig.getInputSpecs().get(topicName).isRegexPattern()) {
throw new IllegalArgumentException(
"isRegexPattern for input topic " + topicName + " cannot be altered");
}
mergedConfig.getInputSpecs().put(topicName, consumerConfig);
});
}
if (!StringUtils.isEmpty(newConfig.getOutputSerdeClassName()) && !newConfig.getOutputSerdeClassName()
.equals(existingConfig.getOutputSerdeClassName())) {
throw new IllegalArgumentException("Output Serde mismatch");
}
if (!StringUtils.isEmpty(newConfig.getOutputSchemaType()) && !newConfig.getOutputSchemaType()
.equals(existingConfig.getOutputSchemaType())) {
throw new IllegalArgumentException("Output Schema mismatch");
}
if (!StringUtils.isEmpty(newConfig.getLogTopic())) {
mergedConfig.setLogTopic(newConfig.getLogTopic());
}
if (newConfig.getProcessingGuarantees() != null && !newConfig.getProcessingGuarantees()
.equals(existingConfig.getProcessingGuarantees())) {
throw new IllegalArgumentException("Processing Guarantees cannot be altered");
}
if (newConfig.getRetainOrdering() != null && !newConfig.getRetainOrdering()
.equals(existingConfig.getRetainOrdering())) {
throw new IllegalArgumentException("Retain Ordering cannot be altered");
}
if (newConfig.getRetainKeyOrdering() != null && !newConfig.getRetainKeyOrdering()
.equals(existingConfig.getRetainKeyOrdering())) {View on GitHub (pinned to 820761864e)
Solutions
- Omit outputSerdeClassName in the update (leave empty) to keep the existing value, or pass the identical existing value.
- To change the output serde, delete and recreate the function with the new serde.
- Check that both configs use the same fully qualified serde class name (package differences also count as mismatch).
Example fix
// before
newConfig.setOutputSerdeClassName("org.apache.pulsar.functions.api.examples.JsonSerde"); // existing: ...StringSerde
// after
newConfig.setOutputSerdeClassName(""); // keep existing serde on update
// or recreate the function with the new serde Defensive patterns
Strategy: validation
Validate before calling
if (newConfig.getOutputSerdeClassName() != null && !newConfig.getOutputSerdeClassName().isEmpty()
&& !newConfig.getOutputSerdeClassName().equals(existingConfig.getOutputSerdeClassName())) {
throw new IllegalArgumentException("outputSerdeClassName is immutable on update");
} Type guard
boolean outputSerdeUnchanged(FunctionConfig existing, FunctionConfig updated) {
String n = updated.getOutputSerdeClassName();
return n == null || n.isEmpty() || n.equals(existing.getOutputSerdeClassName());
} Try / catch
try {
merged = FunctionConfigUtils.validateUpdate(existing, updated);
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("Output Serde mismatch")) {
updated.setOutputSerdeClassName("");
merged = FunctionConfigUtils.validateUpdate(existing, updated);
} else { throw e; }
} Prevention
- Leave outputSerdeClassName empty in update payloads to keep the existing value.
- Use schemaType-based config consistently instead of mixing serdeClassName.
- Recreate the function to change output serialization.
When it happens
Trigger: Updating a function with newConfig.getOutputSerdeClassName() non-empty and != existingConfig.getOutputSerdeClassName().
Common situations: Switching SerDe classes (e.g. from StringSerde to JSONSchema-based serde) on a live function; config template changes; fixing a wrong serde name via update instead of recreate.
Related errors
- Tenants differ
- Namespaces differ
- Function Names differ
- Input Topics cannot be altered
- isRegexPattern for input topic
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/f70a9ca30102f4e8.
Report an issue: GitHub.