{"record":{"id":"98ca0fec26366b7a","repo":"apache/pulsar","slug":"isregexpattern-for-input-topic","errorCode":null,"errorMessage":"isRegexPattern for input topic ","messagePattern":"isRegexPattern for input topic ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":1048,"sourceCode":"                                .build());\n            });\n        }\n        if (newConfig.getCustomSchemaInputs() != null) {\n            newConfig.getCustomSchemaInputs().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            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                mergedConfig.getInputSpecs().put(topicName, consumerConfig);\n            });\n        }\n        if (!StringUtils.isEmpty(newConfig.getOutputSerdeClassName()) && !newConfig.getOutputSerdeClassName()\n                .equals(existingConfig.getOutputSerdeClassName())) {\n            throw new IllegalArgumentException(\"Output Serde mismatch\");\n        }\n        if (!StringUtils.isEmpty(newConfig.getOutputSchemaType()) && !newConfig.getOutputSchemaType()\n                .equals(existingConfig.getOutputSchemaType())) {\n            throw new IllegalArgumentException(\"Output Schema mismatch\");\n        }\n        if (!StringUtils.isEmpty(newConfig.getLogTopic())) {\n            mergedConfig.setLogTopic(newConfig.getLogTopic());\n        }\n        if (newConfig.getProcessingGuarantees() != null && !newConfig.getProcessingGuarantees()\n                .equals(existingConfig.getProcessingGuarantees())) {","sourceCodeStart":1030,"sourceCodeEnd":1066,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L1030-L1066","documentation":"For each input topic already registered on a function, the isRegexPattern flag is immutable: an update cannot convert a plain topic subscription into a regex pattern subscription or vice versa. The message is followed by the offending topic name.","triggerScenarios":"Updating a function where, for a topic present in both existing and new inputSpecs, consumerConfig.isRegexPattern() differs from the existing ConsumerConfig's isRegexPattern() for that topic.","commonSituations":"Switching a topic from exact subscription to pattern (or back) to simplify config; tooling that generates regex:true for all topics by default; merging configs from environments where the flag was set differently.","solutions":["Keep isRegexPattern unchanged for every existing input topic in the update payload.","If the pattern behavior must change, delete and recreate the function with the desired isRegexPattern values.","Check ConsumerConfig construction for defaults that flip isRegexPattern (e.g. builder defaults or YAML `regexPattern:` key)."],"exampleFix":"// before\nConsumerConfig cc = ConsumerConfig.builder().topicName(\"persistent://public/default/t1\")\n    .isRegexPattern(true).build(); // existing has false\n// after\nConsumerConfig cc = ConsumerConfig.builder().topicName(\"persistent://public/default/t1\")\n    .isRegexPattern(existingConfig.getInputSpecs().get(\"persistent://public/default/t1\").isRegexPattern()).build();","handlingStrategy":"validation","validationCode":"newConfig.getInputSpecs().forEach((topic, cc) -> {\n    ConsumerConfig ex = existingConfig.getInputSpecs().get(topic);\n    if (ex != null && ex.isRegexPattern() != cc.isRegexPattern()) {\n        throw new IllegalArgumentException(\"isRegexPattern mismatch for topic \" + topic);\n    }\n});","typeGuard":"boolean regexFlagsUnchanged(FunctionConfig existing, FunctionConfig updated) {\n    return updated.getInputSpecs().entrySet().stream().allMatch(e -> {\n        ConsumerConfig ex = existing.getInputSpecs().get(e.getKey());\n        return ex == null || ex.isRegexPattern() == e.getValue().isRegexPattern();\n    });\n}","tryCatchPattern":"try {\n    merged = FunctionConfigUtils.validateUpdate(existing, updated);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"isRegexPattern for input topic\")) {\n        String topic = e.getMessage().replace(\"isRegexPattern for input topic \", \"\").replace(\" cannot be altered\", \"\");\n        throw new IllegalStateException(\"Recreate the function to change isRegexPattern for \" + topic, e);\n    } else { throw e; }\n}","preventionTips":["Copy isRegexPattern from the existing ConsumerConfig when building update payloads.","Avoid tooling defaults that force isRegexPattern=true.","Diff ConsumerConfig flags between create and update configs."],"tags":["pulsar-functions","immutable-field","update-validation","regex"],"backgroundTag":"immutable-field-update-rejected","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"}