apache/pulsar · error · IllegalArgumentException

Message retries not yet supported in Go function

Error message

Message retries not yet supported in Go function

What it means

Like the Python runtime, the Go function runtime does not implement message retries, so doGolangChecks rejects any Go function config with maxMessageRetries set to a non-negative value. This prevents deploying a Go function that silently ignores retry semantics.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:775

            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)
            throws IllegalArgumentException {
        if (inputTopics.contains(outputTopic)) {
            throw new IllegalArgumentException(
                    String.format(
                            "Output topic %s is also being used as an input topic (topics must be one or the other)",
                            outputTopic));
        }
    }

    public static void doCommonChecks(FunctionConfig functionConfig) {
        if (isEmpty(functionConfig.getTenant())) {
            throw new IllegalArgumentException("Function tenant cannot be null");
        }
        if (isEmpty(functionConfig.getNamespace())) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Remove maxMessageRetries (set to null) or omit --max-message-retries for the Go function
  2. Implement retry logic within the Go function (catch errors, retry with backoff, or republish to a retry/DLQ topic)
  3. Use the Java runtime if built-in message retries are required

Example fix

// before
FunctionConfig config = new FunctionConfig();
config.setRuntime(FunctionConfig.Runtime.GO);
config.setMaxMessageRetries(5);

// after
FunctionConfig config = new FunctionConfig();
config.setRuntime(FunctionConfig.Runtime.GO);
config.setMaxMessageRetries(null); // retries unsupported in Go runtime
Defensive patterns

Strategy: validation

Validate before calling

if (config.getRuntime() == FunctionConfig.Runtime.GO
        && config.getMaxMessageRetries() != null
        && config.getMaxMessageRetries() >= 0) {
    throw new IllegalArgumentException("maxMessageRetries is unsupported for Go functions; remove it");
}
FunctionConfigUtils.validateFunctionConfig(config, null);

Type guard

boolean goRetriesAllowed(FunctionConfig c) {
    return c.getRuntime() != FunctionConfig.Runtime.GO
        || 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 in Go")) {
        config.setMaxMessageRetries(null); // drop unsupported option for Go runtime
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Creating or updating a Go function with setMaxMessageRetries(N) where N != null and N >= 0, or passing --max-message-retries with a --go function create/update command; validated via validateNonJavaFunction -> doGolangChecks.

Common situations: Uniform function-deployment pipelines that set retry counts for all runtimes; retry configs ported from Java functions to Go; operators enabling retries to survive transient processing failures in Go functions.

Related errors


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