{"record":{"id":"a76da524300c2f46","repo":"apache/pulsar","slug":"isregexpattern-for-input-topic-cannot-be-altered","errorCode":null,"errorMessage":"isRegexPattern for input topic  cannot be altered","messagePattern":"isRegexPattern for input topic  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":677,"sourceCode":"            });\n        }\n        if (newConfig.getTopicToSchemaType() != null) {\n            newConfig.getTopicToSchemaType().forEach((topicName, schemaClassname) -> {\n                newConfig.getInputSpecs().put(topicName,\n                        ConsumerConfig.builder()\n                                .schemaType(schemaClassname)\n                                .isRegexPattern(false)\n                                .build());\n            });\n        }\n        if (!newConfig.getInputSpecs().isEmpty()) {\n            SinkConfig finalMergedConfig = mergedConfig;\n            newConfig.getInputSpecs().forEach((topicName, consumerConfig) -> {\n                if (!existingConfig.getInputSpecs().containsKey(topicName)) {\n                    throw new IllegalArgumentException(\"Input Topics cannot be altered\");\n                }\n                if (consumerConfig.isRegexPattern() != existingConfig.getInputSpecs().get(topicName).isRegexPattern()) {\n                    throw new IllegalArgumentException(\n                            \"isRegexPattern for input topic \" + topicName + \" cannot be altered\");\n                }\n                finalMergedConfig.getInputSpecs().put(topicName, consumerConfig);\n            });\n        }\n        if (newConfig.getProcessingGuarantees() != null && !newConfig.getProcessingGuarantees()\n                .equals(existingConfig.getProcessingGuarantees())) {\n            throw new IllegalArgumentException(\"Processing Guarantees cannot be altered\");\n        }\n        if (newConfig.getConfigs() != null) {\n            mergedConfig.setConfigs(newConfig.getConfigs());\n        }\n        if (newConfig.getSecrets() != null) {\n            mergedConfig.setSecrets(newConfig.getSecrets());\n        }\n        if (newConfig.getParallelism() != null) {\n            mergedConfig.setParallelism(newConfig.getParallelism());\n        }","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java#L659-L695","documentation":"Thrown by SinkConfigUtils.validateUpdate when a known input topic's ConsumerConfig.isRegexPattern() flag differs between the existing and new config. Whether a topic is consumed as a regex pattern is fixed at creation time.","triggerScenarios":"Updating a sink whose inputSpecs entry for an existing topic flips isRegexPattern from true to false or vice versa; passing a plain topic name where the sink was created with a regex topic (or the reverse).","commonSituations":"Config migration changes topic declarations from regex 'persistent://public/default/.*' to explicit names; a serializer/tool rewrites topics and toggles the regex flag.","solutions":["Keep isRegexPattern for each input topic identical to the existing sink's value","To change a topic between regex and plain, delete and recreate the sink","Compare each ConsumerConfig.isRegexPattern() with the deployed config before updating"],"exampleFix":"// before\ncc.setRegexPattern(false); // existing sink had true\nsinkConfig.getInputSpecs().put(\"persistent://public/default/.*\", cc);\nadmin.sinks().updateSink(tenant, namespace, sinkConfig, null);\n// after\ncc.setRegexPattern(true); // match existing\nsinkConfig.getInputSpecs().put(\"persistent://public/default/.*\", cc);\nadmin.sinks().updateSink(tenant, namespace, sinkConfig, null);","handlingStrategy":"validation","validationCode":"newCfg.getInputSpecs().forEach((topic, cc) -> {\n    ConsumerConfig old = existing.getInputSpecs().get(topic);\n    if (old != null && cc.isRegexPattern() != old.isRegexPattern()) {\n        throw new IllegalArgumentException(\"isRegexPattern mismatch for \" + topic);\n    }\n});","typeGuard":null,"tryCatchPattern":"try {\n    admin.sinks().updateSink(tenant, namespace, cfg, null);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"isRegexPattern\")) { /* fix regex flag to match existing */ }\n    else throw e;\n}","preventionTips":["Preserve isRegexPattern exactly as deployed for each topic","When rewriting topic strings, keep their regex/plain classification","Check deployed ConsumerConfig values before updating"],"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-14T00:17:10.932Z"}