apache/pulsar · error · IllegalArgumentException
When Guarantees == ATMOST_ONCE, autoAck must be equal to tru
Error message
When Guarantees == ATMOST_ONCE, autoAck must be equal to true. This is a contradictory configuration, autoAck will be removed later. Please refer to PIP: https://github.com/apache/pulsar/issues/15560
What it means
Apache Pulsar function validation rejects a FunctionDetails where autoAck is false while processingGuarantees is ATMOST_ONCE. Manual acking (autoAck=false) is meaningless under at-most-once semantics because messages are not re-delivered, so this combination is contradictory and autoAck is being deprecated in favor of processing guarantees (PIP #15560). validateFunctionDetails enforces this before a function is submitted.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:390
if (!StringUtils.isEmpty(functionConfig.getCustomRuntimeOptions())) {
functionDetails.setCustomRuntimeOptions(functionConfig.getCustomRuntimeOptions());
}
if (isBuiltin) {
String builtin = functionConfig.getJar().replaceFirst("^builtin://", "");
functionDetails.setBuiltin(builtin);
}
return validateFunctionDetails(functionDetails);
}
@SuppressWarnings("deprecation")
public static FunctionDetails validateFunctionDetails(FunctionDetails functionDetails)
throws IllegalArgumentException {
if (!functionDetails.isAutoAck() && functionDetails.getProcessingGuarantees()
== ProcessingGuarantees.ATMOST_ONCE) {
throw new IllegalArgumentException("When Guarantees == ATMOST_ONCE, autoAck must be equal to true."
+ " This is a contradictory configuration, autoAck will be removed later."
+ " Please refer to PIP: https://github.com/apache/pulsar/issues/15560");
}
if (!functionDetails.isAutoAck()) {
log.warn("The autoAck configuration will be deprecated in the future."
+ " If you want not to automatically ack, please configure the processing guarantees as MANUAL.");
}
return functionDetails;
}
@SuppressWarnings("deprecation")
public static FunctionConfig convertFromDetails(FunctionDetails functionDetails) {
functionDetails = validateFunctionDetails(functionDetails);
FunctionConfig functionConfig = new FunctionConfig();
functionConfig.setTenant(functionDetails.getTenant());
functionConfig.setNamespace(functionDetails.getNamespace());
functionConfig.setName(functionDetails.getName());
functionConfig.setParallelism(functionDetails.getParallelism());View on GitHub (pinned to 820761864e)
Solutions
- Set processingGuarantees to MANUAL if you want to ack manually instead of disabling autoAck
- Remove setAutoAck(false) and let ATMOST_ONCE behave with autoAck=true
- Use ATMOST_ONCE with autoAck=true (default) since failed messages are not replayed anyway
Example fix
// before config.setAutoAck(false); config.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATMOST_ONCE); // after config.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.MANUAL);
Defensive patterns
Strategy: validation
Validate before calling
if (cfg.getAutoAck() != null && !cfg.getAutoAck() && cfg.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.ATMOST_ONCE) { throw new IllegalArgumentException("Set processingGuarantees=MANUAL instead of autoAck=false with ATMOST_ONCE"); } Type guard
boolean isConsistentGuarantees(FunctionConfig c) { return !(Boolean.FALSE.equals(c.getAutoAck()) && c.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.ATMOST_ONCE); } Try / catch
try { FunctionConfigUtils.validateFunctionDetails(details); } catch (IllegalArgumentException e) { log.error("Invalid guarantees/autoAck combo: {}", e.getMessage()); } Prevention
- Never set autoAck=false; use MANUAL processing guarantee for manual acking
- Run FunctionConfigUtils.convert on configs in CI before deploying
- Keep up with autoAck deprecation notices (PIP 15560)
When it happens
Trigger: Calling FunctionConfigUtils.convert / convertFromDetails on a config where setAutoAck(false) is combined with setProcessingGuarantees(ATMOST_ONCE), or submitting such a function via the admin API / CLI.
Common situations: Users porting older configs that explicitly disabled autoAck; copy-pasted examples setting autoAck=false while keeping the default ATMOST_ONCE guarantee; migration confusion after the autoAck deprecation.
Related errors
- Function tenant cannot be null
- Function namespace cannot be null
- Function name cannot be null
- there are redundant configure for listener `${listenerName}`
- must not specify `${hostPort}` to different listener.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/a922ddd6259fa6fe.
Report an issue: GitHub.