{"record":{"id":"3e3b8e395a9dca35","repo":"apache/pulsar","slug":"only-one-of-outputschematype-or-outputserdeclassna","errorCode":null,"errorMessage":"Only one of outputSchemaType or outputSerdeClassName should be set","messagePattern":"Only one of outputSchemaType or outputSerdeClassName should be set","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":725,"sourceCode":"                            validatableFunctionPackage.getTypePool(), false);\n                }\n                if (conf.getMessagePayloadProcessorConfig() != null) {\n                    ValidatorUtils.validateMessagePayloadProcessor(conf.getMessagePayloadProcessorConfig(),\n                            validatableFunctionPackage.getTypePool());\n                }\n            });\n        }\n\n        if (Void.class.equals(typeArgs[1])) {\n            return new FunctionConfigUtils.ExtractedFunctionDetails(\n                    functionClassName,\n                    typeArgs[0].asErasure().getTypeName(),\n                    typeArgs[1].asErasure().getTypeName());\n        }\n\n        // One and only one of outputSchemaType and outputSerdeClassName should be set\n        if (!isEmpty(functionConfig.getOutputSerdeClassName()) && !isEmpty(functionConfig.getOutputSchemaType())) {\n            throw new IllegalArgumentException(\n                \"Only one of outputSchemaType or outputSerdeClassName should be set\");\n        }\n\n        if (!isEmpty(functionConfig.getOutputSchemaType())) {\n            ValidatorUtils.validateSchema(functionConfig.getOutputSchemaType(), typeArgs[1],\n                    validatableFunctionPackage.getTypePool(), false);\n        }\n\n        if (!isEmpty(functionConfig.getOutputSerdeClassName())) {\n            ValidatorUtils.validateSerde(functionConfig.getOutputSerdeClassName(), typeArgs[1],\n                    validatableFunctionPackage.getTypePool(), false);\n        }\n\n        if (functionConfig.getProducerConfig() != null\n                && functionConfig.getProducerConfig().getCryptoConfig() != null) {\n            ValidatorUtils\n                    .validateCryptoKeyReader(functionConfig.getProducerConfig().getCryptoConfig(),\n                            validatableFunctionPackage.getTypePool(), true);","sourceCodeStart":707,"sourceCodeEnd":743,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L707-L743","documentation":"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.","triggerScenarios":"FunctionConfig with both setOutputSchemaType(...) and setOutputSerdeClassName(...) non-empty, usually after merging a legacy SerDe config with a schema config.","commonSituations":"Migration from SerDe to schema APIs; templates that set defaults for both fields; tooling that copies fields without clearing the other.","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"],"exampleFix":"// before\nconfig.setOutputSchemaType(\"avro\");\nconfig.setOutputSerdeClassName(\"com.example.OutSerde\");\n// after\nconfig.setOutputSchemaType(\"avro\");","handlingStrategy":"validation","validationCode":"if (notBlank(config.getOutputSerdeClassName()) && notBlank(config.getOutputSchemaType())) { throw new IllegalArgumentException(\"Set only one of outputSchemaType or outputSerdeClassName\"); }","typeGuard":"boolean exclusiveOutputSerializer(FunctionConfig c) { return isBlank(c.getOutputSchemaType()) || isBlank(c.getOutputSerdeClassName()); }","tryCatchPattern":"try { ... } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"outputSchemaType or outputSerdeClassName\")) { log.error(\"Clear one output serializer field\"); } }","preventionTips":["Prefer outputSchemaType for new functions","Explicitly null out the legacy outputSerdeClassName during migration","Lint configs after programmatic merges"],"tags":["pulsar","functions","schema","configuration"],"backgroundTag":"mutually-exclusive-config-options","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}