apache/pulsar · error · IllegalArgumentException

Subscription Name cannot be altered

Error message

Subscription Name cannot be altered

What it means

FunctionConfigUtils.validateUpdate rejects changing the subscription name on an existing function: the subscription identity is fixed at creation, and altering it would orphan the existing subscription state.

Source

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

        }
        if (newConfig.getRuntime() != null && !newConfig.getRuntime().equals(existingConfig.getRuntime())) {
            throw new IllegalArgumentException("Runtime cannot be altered");
        }
        @SuppressWarnings("deprecation")
        boolean autoAckChanged = newConfig.getAutoAck() != null
                && !newConfig.getAutoAck().equals(existingConfig.getAutoAck());
        if (autoAckChanged) {
            throw new IllegalArgumentException("AutoAck cannot be altered");
        }
        if (newConfig.getMaxMessageRetries() != null) {
            mergedConfig.setMaxMessageRetries(newConfig.getMaxMessageRetries());
        }
        if (!StringUtils.isEmpty(newConfig.getDeadLetterTopic())) {
            mergedConfig.setDeadLetterTopic(newConfig.getDeadLetterTopic());
        }
        if (!StringUtils.isEmpty(newConfig.getSubName()) && !newConfig.getSubName()
                .equals(existingConfig.getSubName())) {
            throw new IllegalArgumentException("Subscription Name cannot be altered");
        }
        if (newConfig.getParallelism() != null) {
            mergedConfig.setParallelism(newConfig.getParallelism());
        }
        if (newConfig.getResources() != null) {
            mergedConfig
                    .setResources(ResourceConfigUtils.merge(existingConfig.getResources(), newConfig.getResources()));
        }
        if (newConfig.getWindowConfig() != null) {
            mergedConfig.setWindowConfig(newConfig.getWindowConfig());
        }
        if (newConfig.getTimeoutMs() != null) {
            mergedConfig.setTimeoutMs(newConfig.getTimeoutMs());
        }
        if (newConfig.getCleanupSubscription() != null) {
            mergedConfig.setCleanupSubscription(newConfig.getCleanupSubscription());
        }
        if (!StringUtils.isEmpty(newConfig.getRuntimeFlags())) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep the same subscription name on update
  2. Delete the old subscription explicitly if a rename is truly needed

Example fix

// before
update.setSubName("my-function-sub-v2"); // existing sub differs -> thrown
// after
update.setSubName(existing.getSubName()); // unchanged
Defensive patterns

Strategy: validation

Validate before calling

FunctionConfig existing = admin.functions().getFunction(tenant, namespace, fnName);
if (!StringUtils.isEmpty(update.getSubName()) && !update.getSubName().equals(existing.getSubName())) {
    update.setSubName(null);
}

Try / catch

try {
    admin.functions().updateFunction(update, pkgFile);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Subscription Name")) { /* keep existing subName and retry */ }
    else throw e;
}

Prevention

When it happens

Trigger: Calling updateFunction with a FunctionConfig whose getSubName() is non-empty and differs from existingConfig.getSubName().

Common situations: Renaming the subscription to isolate a stuck consumer; update payloads built from scratch that default subName differently from the deployed function; switching between shared and failover naming conventions.

Related errors


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