{"record":{"id":"96d80674d5fe13de","repo":"apache/pulsar","slug":"only-one-of-serdeclassname-or-schematype-should-be-96d806","errorCode":null,"errorMessage":"Only one of serdeClassName or schemaType should be set","messagePattern":"Only one of serdeClassName or schemaType should be set","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java","lineNumber":344,"sourceCode":"                  String.format(\"Source class %s implements %s but batch source source config is not specified\",\n                    sourceClass.getName(), BatchSource.class.getName()));\n            }\n        }\n\n        // extract type from source class\n        TypeDefinition typeArg;\n\n        try {\n            typeArg = getSourceType(sourceClass);\n        } catch (Exception e) {\n            throw new IllegalArgumentException(\n                    String.format(\"Failed to resolve type for Source class %s\", sourceClassName), e);\n        }\n\n        // Only one of serdeClassName or schemaType should be set\n        if (!StringUtils.isEmpty(sourceConfig.getSerdeClassName()) && !StringUtils\n                .isEmpty(sourceConfig.getSchemaType())) {\n            throw new IllegalArgumentException(\"Only one of serdeClassName or schemaType should be set\");\n        }\n\n        if (!StringUtils.isEmpty(sourceConfig.getSerdeClassName())) {\n            ValidatorUtils.validateSerde(sourceConfig.getSerdeClassName(), typeArg, sourceFunction.getTypePool(),\n                    false);\n        }\n        if (!StringUtils.isEmpty(sourceConfig.getSchemaType())) {\n            ValidatorUtils.validateSchema(sourceConfig.getSchemaType(), typeArg, sourceFunction.getTypePool(),\n                    false);\n        }\n\n        if (sourceConfig.getProducerConfig() != null && sourceConfig.getProducerConfig().getCryptoConfig() != null) {\n            ValidatorUtils\n                    .validateCryptoKeyReader(sourceConfig.getProducerConfig().getCryptoConfig(),\n                            sourceFunction.getTypePool(), true);\n        }\n\n        // validate user defined config if enabled and classloading is enabled","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java#L326-L362","documentation":"Schema configuration conflict in SourceConfigUtils.validateAndExtractDetails: after resolving the source class's type, both serdeClassName and schemaType were set on the SourceConfig, but exactly one serialization mechanism is allowed; the redundant field on the source config is the faulty input.","triggerScenarios":"validateAndExtractDetails finds both sourceConfig.getSerdeClassName() and sourceConfig.getSchemaType() non-empty.","commonSituations":"Merging config templates where one sets schemaType and another serdeClassName; upgrading an old source config by adding schemaType without removing serdeClassName; UI/CLI flags both --serde-classname and --schema-type supplied.","solutions":["Set either serdeClassName or schemaType, not both"],"exampleFix":"// before\n{\"serdeClassName\":\"com.example.MySerde\",\"schemaType\":\"org.apache.pulsar.common.schema.SchemaType.STRING\"}\n// after\n{\"schemaType\":\"org.apache.pulsar.common.schema.SchemaType.STRING\"}","handlingStrategy":"validation","validationCode":"if (config.getSerdeClassName() != null && !config.getSerdeClassName().isEmpty()\n    && config.getSchemaType() != null && !config.getSchemaType().isEmpty()) {\n    throw new IllegalArgumentException(\"Set only one of serdeClassName or schemaType\");\n}","typeGuard":null,"tryCatchPattern":"try { validateAndExtractDetails(...); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"serdeClassName or schemaType\")) { config.setSerdeClassName(null); /* keep schemaType */ } else { throw e; } }","preventionTips":["Standardize on schemaType for new sources","Strip legacy serdeClassName fields when migrating configs","Don't expose both CLI flags at once in tooling","Lint source config JSON for mutually exclusive fields"],"tags":["pulsar-functions","config-validation","ambiguity"],"backgroundTag":"conflicting-parameters","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}