apache/pulsar · error · IllegalArgumentException
Retain Ordering cannot be altered
Error message
Retain Ordering cannot be altered
What it means
Thrown by SinkConfigUtils.validateUpdate when retainOrdering is set and differs from the existing sink's value. Ordering retention is an immutable deployment property; flipping it via update would change how messages are dispatched to sink instances.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java:698
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");
}
@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());
}View on GitHub (pinned to 820761864e)
Solutions
- Set retainOrdering to the same value as the existing sink, or leave it null
- If ordering must change, delete and recreate the sink
- Inspect the deployed config's retainOrdering before updating
Example fix
// before sinkConfig.setRetainOrdering(true); // deployed sink has false admin.sinks().updateSink(tenant, namespace, sinkConfig, null); // after sinkConfig.setRetainOrdering(false); // matches existing admin.sinks().updateSink(tenant, namespace, sinkConfig, null);
Defensive patterns
Strategy: validation
Validate before calling
if (newCfg.getRetainOrdering() != null
&& !newCfg.getRetainOrdering().equals(existing.getRetainOrdering())) {
throw new IllegalArgumentException("retainOrdering is immutable");
} Try / catch
try {
admin.sinks().updateSink(tenant, namespace, cfg, null);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Retain Ordering cannot be altered")) { /* revert retainOrdering */ }
else throw e;
} Prevention
- Leave retainOrdering null on updates
- Recreate the sink if ordering semantics must change
- Keep template configs aligned with deployed values
When it happens
Trigger: Updating a sink with getRetainOrdering() non-null and not equal to the deployed value, e.g. turning ordering on for an existing unordered sink.
Common situations: Developer enables retainOrdering to fix out-of-order processing via update instead of recreate; shared config template sets retainOrdering: true while the deployed sink was created without it.
Related errors
- Sink Names differ
- Subscription Name cannot be altered
- Input Topics cannot be altered
- isRegexPattern for input topic cannot be altered
- Processing Guarantees cannot be altered
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/54e29bace7d6f462.
Report an issue: GitHub.