apache/pulsar · error · IllegalArgumentException
Only one of retain ordering or retain key ordering can be se
Error message
Only one of retain ordering or retain key ordering can be set
What it means
The FunctionConfig rejects setting both retainOrdering=true and retainKeyOrdering=true at the same time. Retain ordering is global message ordering across the function's subscriptions, while retain key ordering is per-key ordering; the framework treats requesting both as ambiguous and throws IllegalArgumentException during config validation in doCommonChecks.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:887
if (functionConfig.getMaxMessageRetries() != null && functionConfig.getMaxMessageRetries() >= 0
&& functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
throw new IllegalArgumentException("MaxMessageRetries and Effectively once don't gel well");
}
if ((functionConfig.getMaxMessageRetries() == null || functionConfig.getMaxMessageRetries() < 0)
&& !org.apache.commons.lang3.StringUtils.isEmpty(functionConfig.getDeadLetterTopic())) {
throw new IllegalArgumentException("Dead Letter Topic specified, however max retries is set to infinity");
}
if (functionConfig.getRetainKeyOrdering() != null
&& functionConfig.getRetainKeyOrdering()
&& functionConfig.getProcessingGuarantees() != null
&& functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
throw new IllegalArgumentException(
"When effectively once processing guarantee is specified, retain Key ordering cannot be set");
}
if (functionConfig.getRetainKeyOrdering() != null && functionConfig.getRetainKeyOrdering()
&& functionConfig.getRetainOrdering() != null && functionConfig.getRetainOrdering()) {
throw new IllegalArgumentException("Only one of retain ordering or retain key ordering can be set");
}
if (!isEmpty(functionConfig.getPy()) && !org.apache.pulsar.common.functions.Utils
.isFunctionPackageUrlSupported(functionConfig.getPy())
&& functionConfig.getPy().startsWith(BUILTIN)) {
String filename = functionConfig.getPy();
if (filename.contains("..")) {
throw new IllegalArgumentException("Invalid filename: " + filename);
}
if (!new File(filename).exists()) {
throw new IllegalArgumentException("The supplied python file does not exist");
}
}
if (!isEmpty(functionConfig.getGo()) && !org.apache.pulsar.common.functions.Utils
.isFunctionPackageUrlSupported(functionConfig.getGo())
&& functionConfig.getGo().startsWith(BUILTIN)) {
String filename = functionConfig.getGo();View on GitHub (pinned to 820761864e)
Solutions
- Pick one ordering mode: remove setRetainKeyOrdering(true) if global ordering is needed
- Remove setRetainOrdering(true) if per-key ordering is what you need
- If ordering is not actually required, set both flags to false/null
Example fix
// before conf.setRetainOrdering(true); conf.setRetainKeyOrdering(true); // after conf.setRetainOrdering(false); conf.setRetainKeyOrdering(true); // only one ordering mode allowed
Defensive patterns
Strategy: validation
Validate before calling
if (Boolean.TRUE.equals(conf.getRetainOrdering()) && Boolean.TRUE.equals(conf.getRetainKeyOrdering())) {
throw new IllegalStateException("Set only one of retainOrdering or retainKeyOrdering");
} Type guard
boolean hasSingleOrderingMode(FunctionConfig c) {
int flags = (Boolean.TRUE.equals(c.getRetainOrdering()) ? 1 : 0)
+ (Boolean.TRUE.equals(c.getRetainKeyOrdering()) ? 1 : 0);
return flags <= 1;
} Try / catch
try {
admin.functions().createFunction(conf);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("retain ordering")) {
conf.setRetainKeyOrdering(false); // prefer global retainOrdering
admin.functions().createFunction(conf);
} else throw e;
} Prevention
- Treat the two ordering flags as an enum-like choice in your config layer
- When toggling one flag on, explicitly clear the other
- Document in team config templates which ordering mode each pipeline uses
When it happens
Trigger: Creating or updating a function with a FunctionConfig where setRetainOrdering(true) and setRetainKeyOrdering(true) are both present, via validateJavaFunction/validateNonJavaFunction or the REST admin API.
Common situations: Merging config from two templates that each set one of the flags; toggling between global and key-based ordering by adding the second flag instead of switching; misunderstanding the flags as independent toggles that can be combined.
Related errors
- When effectively once processing guarantee is specified, ret
- Receiver queue size should be >= zero
- Source tenant cannot be null
- Source namespace cannot be null
- Source name cannot be null
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/80ee80da8a1c4812.
Report an issue: GitHub.