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

  1. Pick one ordering mode: remove setRetainKeyOrdering(true) if global ordering is needed
  2. Remove setRetainOrdering(true) if per-key ordering is what you need
  3. 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

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


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