apache/pulsar · error · IllegalArgumentException
Only one of outputSchemaType or outputSerdeClassName should
Error message
Only one of outputSchemaType or outputSerdeClassName should be set
What it means
The function's output serialization must be declared exactly one way: outputSchemaType or outputSerdeClassName. doJavaChecks throws IllegalArgumentException when both are set, mirroring the inputSpec rule.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:725
validatableFunctionPackage.getTypePool(), false);
}
if (conf.getMessagePayloadProcessorConfig() != null) {
ValidatorUtils.validateMessagePayloadProcessor(conf.getMessagePayloadProcessorConfig(),
validatableFunctionPackage.getTypePool());
}
});
}
if (Void.class.equals(typeArgs[1])) {
return new FunctionConfigUtils.ExtractedFunctionDetails(
functionClassName,
typeArgs[0].asErasure().getTypeName(),
typeArgs[1].asErasure().getTypeName());
}
// One and only one of outputSchemaType and outputSerdeClassName should be set
if (!isEmpty(functionConfig.getOutputSerdeClassName()) && !isEmpty(functionConfig.getOutputSchemaType())) {
throw new IllegalArgumentException(
"Only one of outputSchemaType or outputSerdeClassName should be set");
}
if (!isEmpty(functionConfig.getOutputSchemaType())) {
ValidatorUtils.validateSchema(functionConfig.getOutputSchemaType(), typeArgs[1],
validatableFunctionPackage.getTypePool(), false);
}
if (!isEmpty(functionConfig.getOutputSerdeClassName())) {
ValidatorUtils.validateSerde(functionConfig.getOutputSerdeClassName(), typeArgs[1],
validatableFunctionPackage.getTypePool(), false);
}
if (functionConfig.getProducerConfig() != null
&& functionConfig.getProducerConfig().getCryptoConfig() != null) {
ValidatorUtils
.validateCryptoKeyReader(functionConfig.getProducerConfig().getCryptoConfig(),
validatableFunctionPackage.getTypePool(), true);View on GitHub (pinned to 820761864e)
Solutions
- Keep outputSchemaType and clear outputSerdeClassName (recommended)
- Or keep outputSerdeClassName and clear outputSchemaType for legacy usage
- Check the config after programmatic merges so only one output serializer field remains set
Example fix
// before
config.setOutputSchemaType("avro");
config.setOutputSerdeClassName("com.example.OutSerde");
// after
config.setOutputSchemaType("avro"); Defensive patterns
Strategy: validation
Validate before calling
if (notBlank(config.getOutputSerdeClassName()) && notBlank(config.getOutputSchemaType())) { throw new IllegalArgumentException("Set only one of outputSchemaType or outputSerdeClassName"); } Type guard
boolean exclusiveOutputSerializer(FunctionConfig c) { return isBlank(c.getOutputSchemaType()) || isBlank(c.getOutputSerdeClassName()); } Try / catch
try { ... } catch (IllegalArgumentException e) { if (e.getMessage().contains("outputSchemaType or outputSerdeClassName")) { log.error("Clear one output serializer field"); } } Prevention
- Prefer outputSchemaType for new functions
- Explicitly null out the legacy outputSerdeClassName during migration
- Lint configs after programmatic merges
When it happens
Trigger: FunctionConfig with both setOutputSchemaType(...) and setOutputSerdeClassName(...) non-empty, usually after merging a legacy SerDe config with a schema config.
Common situations: Migration from SerDe to schema APIs; templates that set defaults for both fields; tooling that copies fields without clearing the other.
Related errors
- Only one of schemaType or serdeClassName should be set in in
- When Guarantees == ATMOST_ONCE, autoAck must be equal to tru
- Function class name is not provided.
- Topic %s has an incorrect schema Info
- Function tenant cannot be null
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/3e3b8e395a9dca35.
Report an issue: GitHub.