{"record":{"id":"469855f5b6b35f79","repo":"apache/pulsar","slug":"namespaces-differ-469855","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/SinkConfigUtils.java","lineNumber":616,"sourceCode":"            retval.addAll(sinkConfig.getInputSpecs().keySet());\n        }\n        return retval;\n    }\n\n    @SneakyThrows\n    public static SinkConfig clone(SinkConfig sinkConfig) {\n        return ObjectMapperFactory.getMapper().reader().readValue(\n                ObjectMapperFactory.getMapper().writer().writeValueAsBytes(sinkConfig), SinkConfig.class);\n    }\n\n    public static SinkConfig validateUpdate(SinkConfig existingConfig, SinkConfig newConfig) {\n        SinkConfig mergedConfig = clone(existingConfig);\n\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(\"Sink Names differ\");\n        }\n        if (!StringUtils.isEmpty(newConfig.getClassName())) {\n            mergedConfig.setClassName(newConfig.getClassName());\n        }\n        if (!StringUtils.isEmpty(newConfig.getSourceSubscriptionName()) && !newConfig.getSourceSubscriptionName()\n                .equals(existingConfig.getSourceSubscriptionName())) {\n            throw new IllegalArgumentException(\"Subscription Name cannot be altered\");\n        }\n\n        if (newConfig.getInputSpecs() == null) {\n            newConfig.setInputSpecs(new HashMap<>());\n        }\n\n        if (mergedConfig.getInputSpecs() == null) {\n            mergedConfig.setInputSpecs(new HashMap<>());","sourceCodeStart":598,"sourceCodeEnd":634,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java#L598-L634","documentation":"Update-compatibility check in SinkConfigUtils.validateUpdate: the existing and new sink configurations live in different namespaces, which would relocate the sink; sink updates must preserve tenant/namespace/name identity, so the differing namespace fields are rejected.","triggerScenarios":"Calling validateUpdate with a newConfig whose getNamespace() differs from existingConfig.getNamespace().","commonSituations":"Copying a sink config template across namespaces; admin tooling that rebuilds config from request body where namespace field was changed; trying to 'move' a sink via update.","solutions":["Keep the namespace unchanged; recreate the sink elsewhere if needed"],"exampleFix":"// before\nnewConfig.setNamespace(\"ns2\");\nSinkConfig merged = SinkConfigUtils.validateUpdate(existing, newConfig);\n// after\nnewConfig.setNamespace(existing.getNamespace());\nSinkConfig merged = SinkConfigUtils.validateUpdate(existing, newConfig);","handlingStrategy":"validation","validationCode":"if (!existing.getNamespace().equals(newConfig.getNamespace())) {\n  throw new IllegalStateException(\"Update cannot change namespace; delete+create instead\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  admin.sinks().updateSink(tenant, ns, name, newConfig);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().equals(\"Namespaces differ\")) {\n    // recreate sink in target namespace via createSink\n  } else { throw e; }\n}","preventionTips":["Clone existing config and mutate only allowed fields for updates","Take namespace from the REST path, not the request body"],"tags":["pulsar-functions","sink","update","validation"],"backgroundTag":"identity-mismatch-on-update","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"}