apache/pulsar · error · IllegalArgumentException

AutoAck cannot be altered

Error message

AutoAck cannot be altered

What it means

FunctionConfigUtils.validateUpdate rejects changing the autoAck setting on an existing function: autoAck is immutable after creation because it changes acknowledgement semantics for in-flight messages.

Source

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

            throw new IllegalArgumentException("Retain Key Ordering cannot be altered");
        }
        if (!StringUtils.isEmpty(newConfig.getOutput())) {
            mergedConfig.setOutput(newConfig.getOutput());
        }
        if (newConfig.getUserConfig() != null) {
            mergedConfig.setUserConfig(newConfig.getUserConfig());
        }
        if (newConfig.getSecrets() != null) {
            mergedConfig.setSecrets(newConfig.getSecrets());
        }
        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()));
        }

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep autoAck unchanged in the update request
  2. Recreate the function if autoAck must change

Example fix

// before
update.setAutoAck(false); // deprecated + differs -> thrown
// after
update.setAutoAck(null); // leave deprecated field unset
Defensive patterns

Strategy: validation

Validate before calling

if (update.getAutoAck() != null) {
    update.setAutoAck(null); // deprecated field; leave unset on updates
}

Try / catch

try {
    admin.functions().updateFunction(update, pkgFile);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("AutoAck")) { /* clear autoAck and retry */ }
    else throw e;
}

Prevention

When it happens

Trigger: Updating a function where getAutoAck() is non-null and differs from the existing config's autoAck value.

Common situations: Old configs or legacy tooling that still set autoAck; SDK clients carrying autoAck=true/false defaults from older Pulsar versions into update requests.

Related errors


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