{"record":{"id":"e0a80ab1a23bf2a0","repo":"apache/pulsar","slug":"namespaces-differ-e0a80a","errorCode":null,"errorMessage":"Namespaces differ","messagePattern":"Namespaces differ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java","lineNumber":386,"sourceCode":"            }\n        }\n\n        return new ExtractedSourceDetails(sourceClassName, typeArg.asErasure().getTypeName());\n    }\n\n    @SneakyThrows\n    public static SourceConfig clone(SourceConfig sourceConfig) {\n        return ObjectMapperFactory.getMapper().reader().readValue(\n                ObjectMapperFactory.getMapper().writer().writeValueAsBytes(sourceConfig), SourceConfig.class);\n    }\n\n    public static SourceConfig validateUpdate(SourceConfig existingConfig, SourceConfig newConfig) {\n        SourceConfig mergedConfig = clone(existingConfig);\n        if (!existingConfig.getTenant().equals(newConfig.getTenant())) {\n            throw new IllegalArgumentException(\"Tenants differ\");\n        }\n        if (!existingConfig.getNamespace().equals(newConfig.getNamespace())) {\n            throw new IllegalArgumentException(\"Namespaces differ\");\n        }\n        if (!existingConfig.getName().equals(newConfig.getName())) {\n            throw new IllegalArgumentException(\"Function Names differ\");\n        }\n        if (!StringUtils.isEmpty(newConfig.getClassName())) {\n            mergedConfig.setClassName(newConfig.getClassName());\n        }\n        if (!StringUtils.isEmpty(newConfig.getTopicName())) {\n            mergedConfig.setTopicName(newConfig.getTopicName());\n        }\n        if (!StringUtils.isEmpty(newConfig.getSerdeClassName())) {\n            mergedConfig.setSerdeClassName(newConfig.getSerdeClassName());\n        }\n        if (!StringUtils.isEmpty(newConfig.getSchemaType())) {\n            mergedConfig.setSchemaType(newConfig.getSchemaType());\n        }\n        if (newConfig.getConfigs() != null) {\n            mergedConfig.setConfigs(newConfig.getConfigs());","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java#L368-L404","documentation":"validateUpdate requires the namespace of the source to remain unchanged across updates. Sources are addressed by tenant/namespace/name; changing the namespace would repoint the source's identity and topics, so it is rejected.","triggerScenarios":"validateUpdate is given a newConfig whose getNamespace() differs from existingConfig.getNamespace(), e.g. an update request submitted under a different namespace than where the source was created.","commonSituations":"Submitting the update against the wrong namespace endpoint while the config body names the original namespace (or vice versa); renaming/refactoring namespaces in templates; moving sources during environment migration.","solutions":["Resubmit the update with namespace identical to the existing source's namespace","Call the update API on the correct tenant/namespace where the source lives","To relocate the source, delete and recreate it in the target namespace"],"exampleFix":"// before\n{\"tenant\":\"t1\",\"namespace\":\"ns2\",\"name\":\"src1\", ...}\n// after\n{\"tenant\":\"t1\",\"namespace\":\"ns1\",\"name\":\"src1\", ...}","handlingStrategy":"validation","validationCode":"if (!Objects.equals(existing.getNamespace(), update.getNamespace())) {\n    throw new IllegalArgumentException(\"namespace is immutable on update\");\n}","typeGuard":null,"tryCatchPattern":"try { SourceConfigUtils.validateUpdate(existing, update); } catch (IllegalArgumentException e) { if (e.getMessage().equals(\"Namespaces differ\")) { update.setNamespace(existing.getNamespace()); } else { throw e; } }","preventionTips":["Call the update API on the exact tenant/namespace where the source was created","Preserve the namespace field from the existing config in update payloads","Avoid namespace refactors in shared templates without recreating sources"],"tags":["pulsar-functions","immutable-field","update-validation"],"backgroundTag":"immutable-field-change","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"}