apache/pulsar · error · IllegalArgumentException
Message retries not yet supported in python
Error message
Message retries not yet supported in python
What it means
Pulsar Functions validates function configurations per runtime language. The Python runtime does not implement the message-retry feature (maxMessageRetries), so doPythonChecks rejects any Python function config where maxMessageRetries is set to a non-negative value. This is a deliberate guard against silently ignoring a retry setting that would have no effect.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:761
validatableFunctionPackage.getTypePool(), true);
}
return new FunctionConfigUtils.ExtractedFunctionDetails(
functionClassName,
typeArgs[0].asErasure().getTypeName(),
typeArgs[1].asErasure().getTypeName());
}
private static void doPythonChecks(FunctionConfig functionConfig) {
if (functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
throw new RuntimeException("Effectively-once processing guarantees not yet supported in Python");
}
if (functionConfig.getWindowConfig() != null) {
throw new IllegalArgumentException("There is currently no support windowing in python");
}
if (functionConfig.getMaxMessageRetries() != null && functionConfig.getMaxMessageRetries() >= 0) {
throw new IllegalArgumentException("Message retries not yet supported in python");
}
}
private static void doGolangChecks(FunctionConfig functionConfig) {
if (functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
throw new RuntimeException("Effectively-once processing guarantees not yet supported in Go function");
}
if (functionConfig.getWindowConfig() != null) {
throw new IllegalArgumentException("Windowing is not supported in Go function yet");
}
if (functionConfig.getMaxMessageRetries() != null && functionConfig.getMaxMessageRetries() >= 0) {
throw new IllegalArgumentException("Message retries not yet supported in Go function");
}
}
private static void verifyNoTopicClash(Collection<String> inputTopics, String outputTopic)View on GitHub (pinned to 820761864e)
Solutions
- Remove maxMessageRetries (or set it to null / leave --max-message-retries unset) from the Python function config
- Handle retries inside the Python function logic itself (catch exceptions, track attempts, re-publish to a retry topic)
- Migrate the function to the Java runtime if message retries are a hard requirement
Example fix
// before FunctionConfig config = new FunctionConfig(); config.setRuntime(FunctionConfig.Runtime.PYTHON); config.setMaxMessageRetries(3); // after FunctionConfig config = new FunctionConfig(); config.setRuntime(FunctionConfig.Runtime.PYTHON); config.setMaxMessageRetries(null); // retries unsupported in Python runtime
Defensive patterns
Strategy: validation
Validate before calling
if (config.getRuntime() == FunctionConfig.Runtime.PYTHON
&& config.getMaxMessageRetries() != null
&& config.getMaxMessageRetries() >= 0) {
throw new IllegalArgumentException("maxMessageRetries is unsupported for Python functions; remove it");
}
FunctionConfigUtils.validateFunctionConfig(config, null); // only after the guard passes Type guard
boolean pythonRetriesAllowed(FunctionConfig c) {
return c.getRuntime() != FunctionConfig.Runtime.PYTHON
|| c.getMaxMessageRetries() == null
|| c.getMaxMessageRetries() < 0;
} Try / catch
try {
FunctionConfigUtils.validateFunctionConfig(config, null);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("Message retries not yet supported")) {
config.setMaxMessageRetries(null); // drop unsupported option for Python runtime
} else {
throw e;
}
} Prevention
- Never set maxMessageRetries in configs used for Python or Go functions
- Keep per-runtime config templates instead of a shared config for Java/Python/Go functions
- Validate configs in CI before deployment with FunctionConfigUtils or a dry-run create
- Check runtime feature-parity tables before copying Java function options to Python/Go
When it happens
Trigger: Creating or updating a Python function (pulsar-admin functions create/update, or FunctionConfigUtils.validateNonJavaFunction) with setMaxMessageRetries(N) where N != null and N >= 0, or equivalently passing --max-message-retries on the CLI for a --py function.
Common situations: Copy-pasting a Java function config to a Python function; enabling retries to handle processing failures; templates or CI pipelines that set maxMessageRetries uniformly for all functions regardless of runtime.
Related errors
- V5 does not support non-persistent:// topics: + topic
- unknown auth provider: %s
- Go instance current not support EFFECTIVELY_ONCE processing
- Unknown component type: %s
- Access to environment variable %s is not allowed.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/096166bb560f2098.
Report an issue: GitHub.