apache/pulsar · error · IllegalArgumentException

Processing Guarantees cannot be altered

Error message

Processing Guarantees cannot be altered

What it means

The processing guarantees (at-most-once, at-least-once, effectively-once) of a source cannot be changed after creation, because it affects how state and delivery semantics are managed. validateUpdate rejects any attempt to alter it.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java:414

        }
        if (!StringUtils.isEmpty(newConfig.getSerdeClassName())) {
            mergedConfig.setSerdeClassName(newConfig.getSerdeClassName());
        }
        if (!StringUtils.isEmpty(newConfig.getSchemaType())) {
            mergedConfig.setSchemaType(newConfig.getSchemaType());
        }
        if (newConfig.getConfigs() != null) {
            mergedConfig.setConfigs(newConfig.getConfigs());
        }
        if (newConfig.getSecrets() != null) {
            mergedConfig.setSecrets(newConfig.getSecrets());
        }
        if (!StringUtils.isEmpty(newConfig.getLogTopic())) {
            mergedConfig.setLogTopic(newConfig.getLogTopic());
        }
        if (newConfig.getProcessingGuarantees() != null && !newConfig.getProcessingGuarantees()
                .equals(existingConfig.getProcessingGuarantees())) {
            throw new IllegalArgumentException("Processing Guarantees cannot be altered");
        }
        if (newConfig.getParallelism() != null) {
            mergedConfig.setParallelism(newConfig.getParallelism());
        }
        if (newConfig.getResources() != null) {
            mergedConfig
                    .setResources(ResourceConfigUtils.merge(existingConfig.getResources(), newConfig.getResources()));
        }
        if (!StringUtils.isEmpty(newConfig.getArchive())) {
            mergedConfig.setArchive(newConfig.getArchive());
        }
        if (!StringUtils.isEmpty(newConfig.getRuntimeFlags())) {
            mergedConfig.setRuntimeFlags(newConfig.getRuntimeFlags());
        }
        if (!StringUtils.isEmpty(newConfig.getCustomRuntimeOptions())) {
            mergedConfig.setCustomRuntimeOptions(newConfig.getCustomRuntimeOptions());
        }
        if (isBatchSource(existingConfig) != isBatchSource(newConfig)) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Resubmit the update with processingGuarantees either omitted (null) or equal to the existing value
  2. If the guarantee must change, delete and recreate the source with the new guarantee
  3. Update tooling to preserve the existing processingGuarantees on update calls

Example fix

// before
{"processingGuarantees":"EFFECTIVELY_ONCE", ...} // existing is ATLEAST_ONCE
// after
omit processingGuarantees from the update payload, or set it to "ATLEAST_ONCE"
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

try { SourceConfigUtils.validateUpdate(existing, update); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Processing Guarantees")) { update.setProcessingGuarantees(null); /* omit from update */ } else { throw e; } }

Prevention

When it happens

Trigger: validateUpdate sees newConfig.getProcessingGuarantees() != null and not equal to existingConfig.getProcessingGuarantees().

Common situations: Operator tries to strengthen delivery guarantees on a live source via update; config template regenerated with a different default guarantee; tooling that always populates processingGuarantees with the template's value instead of the existing one.

Related errors


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