{"record":{"id":"c2381b2d490f87a7","repo":"apache/pulsar","slug":"subscription-name-cannot-be-altered-c2381b","errorCode":null,"errorMessage":"Subscription Name cannot be altered","messagePattern":"Subscription Name cannot be altered","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java","lineNumber":626,"sourceCode":"\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<>());\n        }\n        if (!StringUtils.isEmpty(newConfig.getLogTopic())) {\n            mergedConfig.setLogTopic(newConfig.getLogTopic());\n        }\n\n        if (newConfig.getInputs() != null) {\n            newConfig.getInputs().forEach((topicName -> {\n                newConfig.getInputSpecs().putIfAbsent(topicName,\n                        ConsumerConfig.builder().isRegexPattern(false).build());\n            }));","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java#L608-L644","documentation":"Thrown by SinkConfigUtils.validateUpdate when sourceSubscriptionName is set in the new config and differs from the existing one. The Pulsar subscription a sink consumes from is fixed after creation, so changing it is rejected to avoid silently switching the consumption source.","triggerScenarios":"Updating a sink while passing a non-empty getSourceSubscriptionName() that does not equal the existing config's subscription name (including changing it from a configured value to a different one).","commonSituations":"Teams rename subscriptions in shared config; a sink created with subscription 'sub-a' is updated with 'sub-b'; user tries to point an existing sink at a different topic subscription instead of recreating it.","solutions":["Set sourceSubscriptionName in the update config to the same value as the existing sink (or leave it empty to keep it)","If a different subscription is required, delete and re-create the sink with the new subscription name","Check the current value via 'pulsar-admin sinks get' before updating"],"exampleFix":"// before\nsinkConfig.setSourceSubscriptionName(\"new-sub\");\nadmin.sinks().updateSink(tenant, namespace, sinkConfig, null);\n// after\nsinkConfig.setSourceSubscriptionName(\"original-sub\"); // must match existing\nadmin.sinks().updateSink(tenant, namespace, sinkConfig, null);","handlingStrategy":"validation","validationCode":"if (newCfg.getSourceSubscriptionName() != null\n    && !newCfg.getSourceSubscriptionName().isEmpty()\n    && !newCfg.getSourceSubscriptionName().equals(existing.getSourceSubscriptionName())) {\n    throw new IllegalArgumentException(\"sourceSubscriptionName is immutable\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.sinks().updateSink(tenant, namespace, cfg, null);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Subscription Name cannot be altered\")) { /* revert to existing subscription */ }\n    else throw e;\n}","preventionTips":["Leave sourceSubscriptionName unset in update payloads","Keep one canonical source-of-truth config per sink to avoid drifted subscription names","Recreate the sink if the subscription must change"],"tags":["pulsar","functions","config-validation","immutable-field"],"backgroundTag":"immutable-config-field-update","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"}