apache/pulsar · error · IllegalArgumentException

isRegexPattern for input topic

Error message

isRegexPattern for input topic 

What it means

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.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:1048

                                .build());
            });
        }
        if (newConfig.getCustomSchemaInputs() != null) {
            newConfig.getCustomSchemaInputs().forEach((topicName, schemaClassname) -> {
                newConfig.getInputSpecs().put(topicName,
                        ConsumerConfig.builder()
                                .schemaType(schemaClassname)
                                .isRegexPattern(false)
                                .build());
            });
        }
        if (!newConfig.getInputSpecs().isEmpty()) {
            newConfig.getInputSpecs().forEach((topicName, consumerConfig) -> {
                if (!existingConfig.getInputSpecs().containsKey(topicName)) {
                    throw new IllegalArgumentException("Input Topics cannot be altered");
                }
                if (consumerConfig.isRegexPattern() != existingConfig.getInputSpecs().get(topicName).isRegexPattern()) {
                    throw new IllegalArgumentException(
                            "isRegexPattern for input topic " + topicName + " cannot be altered");
                }
                mergedConfig.getInputSpecs().put(topicName, consumerConfig);
            });
        }
        if (!StringUtils.isEmpty(newConfig.getOutputSerdeClassName()) && !newConfig.getOutputSerdeClassName()
                .equals(existingConfig.getOutputSerdeClassName())) {
            throw new IllegalArgumentException("Output Serde mismatch");
        }
        if (!StringUtils.isEmpty(newConfig.getOutputSchemaType()) && !newConfig.getOutputSchemaType()
                .equals(existingConfig.getOutputSchemaType())) {
            throw new IllegalArgumentException("Output Schema mismatch");
        }
        if (!StringUtils.isEmpty(newConfig.getLogTopic())) {
            mergedConfig.setLogTopic(newConfig.getLogTopic());
        }
        if (newConfig.getProcessingGuarantees() != null && !newConfig.getProcessingGuarantees()
                .equals(existingConfig.getProcessingGuarantees())) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep isRegexPattern unchanged for every existing input topic in the update payload.
  2. If the pattern behavior must change, delete and recreate the function with the desired isRegexPattern values.
  3. Check ConsumerConfig construction for defaults that flip isRegexPattern (e.g. builder defaults or YAML `regexPattern:` key).

Example fix

// before
ConsumerConfig cc = ConsumerConfig.builder().topicName("persistent://public/default/t1")
    .isRegexPattern(true).build(); // existing has false
// after
ConsumerConfig cc = ConsumerConfig.builder().topicName("persistent://public/default/t1")
    .isRegexPattern(existingConfig.getInputSpecs().get("persistent://public/default/t1").isRegexPattern()).build();
Defensive patterns

Strategy: validation

Validate before calling

newConfig.getInputSpecs().forEach((topic, cc) -> {
    ConsumerConfig ex = existingConfig.getInputSpecs().get(topic);
    if (ex != null && ex.isRegexPattern() != cc.isRegexPattern()) {
        throw new IllegalArgumentException("isRegexPattern mismatch for topic " + topic);
    }
});

Type guard

boolean regexFlagsUnchanged(FunctionConfig existing, FunctionConfig updated) {
    return updated.getInputSpecs().entrySet().stream().allMatch(e -> {
        ConsumerConfig ex = existing.getInputSpecs().get(e.getKey());
        return ex == null || ex.isRegexPattern() == e.getValue().isRegexPattern();
    });
}

Try / catch

try {
    merged = FunctionConfigUtils.validateUpdate(existing, updated);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("isRegexPattern for input topic")) {
        String topic = e.getMessage().replace("isRegexPattern for input topic ", "").replace(" cannot be altered", "");
        throw new IllegalStateException("Recreate the function to change isRegexPattern for " + topic, e);
    } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/98ca0fec26366b7a. Report an issue: GitHub.