apache/pulsar · error · IllegalArgumentException

Retain Key Ordering cannot be altered

Error message

Retain Key Ordering cannot be altered

What it means

Thrown by SinkConfigUtils.validateUpdate when retainKeyOrdering is set and differs from the existing sink's value. Like retainOrdering, key ordering is fixed at creation and cannot be changed through the update path.

Source

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

                .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");
        }
        @SuppressWarnings("deprecation")
        boolean autoAckChanged = newConfig.getAutoAck() != null
                && !newConfig.getAutoAck().equals(existingConfig.getAutoAck());
        if (autoAckChanged) {
            throw new IllegalArgumentException("AutoAck cannot be altered");
        }
        if (newConfig.getResources() != null) {
            mergedConfig
                    .setResources(ResourceConfigUtils.merge(existingConfig.getResources(), newConfig.getResources()));
        }
        if (newConfig.getTimeoutMs() != null) {
            mergedConfig.setTimeoutMs(newConfig.getTimeoutMs());
        }
        if (newConfig.getCleanupSubscription() != null) {
            mergedConfig.setCleanupSubscription(newConfig.getCleanupSubscription());
        }
        if (!StringUtils.isEmpty(newConfig.getArchive())) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep retainKeyOrdering identical to the existing sink's value (or null)
  2. Delete and recreate the sink if key ordering must change
  3. Verify the deployed value via 'pulsar-admin sinks get' before updating

Example fix

// before
sinkConfig.setRetainKeyOrdering(true); // deployed sink has false
admin.sinks().updateSink(tenant, namespace, sinkConfig, null);
// after
sinkConfig.setRetainKeyOrdering(false); // matches existing
admin.sinks().updateSink(tenant, namespace, sinkConfig, null);
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

try {
    admin.sinks().updateSink(tenant, namespace, cfg, null);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Retain Key Ordering cannot be altered")) { /* revert retainKeyOrdering */ }
    else throw e;
}

Prevention

When it happens

Trigger: Updating a sink with getRetainKeyOrdering() non-null and different from the deployed config's value.

Common situations: Enabling per-key ordering on an already deployed sink via update; a config template with retainKeyOrdering enabled is reused to update a sink created without it.

Related errors


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