apache/pulsar · error · IllegalArgumentException

Processing Guarantees cannot be altered

Error message

Processing Guarantees cannot be altered

What it means

Thrown by SinkConfigUtils.validateUpdate when processingGuarantees is set in the new config and differs from the existing sink's value. The delivery semantics (ATLEAST_ONCE, ATMOST_ONCE, EFFECTIVELY_ONCE) are locked after creation because changing them affects message acknowledgment behavior.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java:685

                                .build());
            });
        }
        if (!newConfig.getInputSpecs().isEmpty()) {
            SinkConfig finalMergedConfig = mergedConfig;
            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");
                }
                finalMergedConfig.getInputSpecs().put(topicName, consumerConfig);
            });
        }
        if (newConfig.getProcessingGuarantees() != null && !newConfig.getProcessingGuarantees()
                .equals(existingConfig.getProcessingGuarantees())) {
            throw new IllegalArgumentException("Processing Guarantees cannot be altered");
        }
        if (newConfig.getConfigs() != null) {
            mergedConfig.setConfigs(newConfig.getConfigs());
        }
        if (newConfig.getSecrets() != null) {
            mergedConfig.setSecrets(newConfig.getSecrets());
        }
        if (newConfig.getParallelism() != null) {
            mergedConfig.setParallelism(newConfig.getParallelism());
        }
        if (newConfig.getRetainOrdering() != null && !newConfig.getRetainOrdering()
                .equals(existingConfig.getRetainOrdering())) {
            throw new IllegalArgumentException("Retain Ordering cannot be altered");
        }
        if (newConfig.getRetainKeyOrdering() != null && !newConfig.getRetainKeyOrdering()
                .equals(existingConfig.getRetainKeyOrdering())) {
            throw new IllegalArgumentException("Retain Key Ordering cannot be altered");
        }

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep processingGuarantees equal to the existing sink's value (or null to leave it unchanged)
  2. To change guarantees, delete the sink and create it anew with the desired setting
  3. Check the deployed value with 'pulsar-admin sinks get' before setting the field

Example fix

// before
sinkConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE);
admin.sinks().updateSink(tenant, namespace, sinkConfig, null);
// after
sinkConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); // matches existing
admin.sinks().updateSink(tenant, namespace, sinkConfig, null);
Defensive patterns

Strategy: validation

Validate before calling

if (newCfg.getProcessingGuarantees() != null
    && !newCfg.getProcessingGuarantees().equals(existing.getProcessingGuarantees())) {
    throw new IllegalArgumentException("processingGuarantees is immutable");
}

Try / catch

try {
    admin.sinks().updateSink(tenant, namespace, cfg, null);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Processing Guarantees cannot be altered")) { /* keep existing guarantee */ }
    else throw e;
}

Prevention

When it happens

Trigger: Updating a sink with getProcessingGuarantees() non-null and not equal to the deployed value, e.g. switching ATLEAST_ONCE to EFFECTIVELY_ONCE via update.

Common situations: Team hardens delivery guarantees on an existing sink via update; template config carries a different default guarantee than the deployed sink; copy-paste between function and sink configs with different guarantees.

Related errors


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