apache/pulsar · error · RuntimeException

Effectively-once processing guarantees not yet supported in

Error message

Effectively-once processing guarantees not yet supported in Go function

What it means

The Go function runtime does not support EFFECTIVELY_ONCE processing guarantees, so doGolangChecks rejects any Go function config requesting that mode. Effectively-once requires deduplication/ack semantics the Go runtime has not implemented, and the check prevents silently downgrading the guarantee.

Source

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

    }

    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)
            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));

View on GitHub (pinned to 820761864e)

Solutions

  1. Set processingGuarantees to ATLEAST_ONCE (or ATMOST_ONCE) for the Go function
  2. Implement idempotent processing in the Go function (dedupe by message id/key on the output side)
  3. Enable topic-level producer deduplication on the output topic as a partial effectively-once substitute
  4. Move the function to the Java runtime if EFFECTIVELY_ONCE is mandatory

Example fix

// before
FunctionConfig config = new FunctionConfig();
config.setRuntime(FunctionConfig.Runtime.GO);
config.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE);

// after
FunctionConfig config = new FunctionConfig();
config.setRuntime(FunctionConfig.Runtime.GO);
config.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE);
Defensive patterns

Strategy: validation

Validate before calling

if (config.getRuntime() == FunctionConfig.Runtime.GO
        && config.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
    throw new IllegalArgumentException("EFFECTIVELY_ONCE is unsupported for Go functions");
}
FunctionConfigUtils.validateFunctionConfig(config, null);

Type guard

boolean goProcessingGuaranteeSupported(FunctionConfig c) {
    return c.getRuntime() != FunctionConfig.Runtime.GO
        || c.getProcessingGuarantees() != FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE;
}

Try / catch

try {
    FunctionConfigUtils.validateFunctionConfig(config, null);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Effectively-once processing guarantees not yet supported in Go")) {
        config.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); // degrade explicitly
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Creating or updating a Go function with setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) (or --processing-guarantees EFFECTIVELY_ONCE on the CLI for a --go function), which flows through validateNonJavaFunction -> doGolangChecks.

Common situations: Reusing a config that worked for a Java function (which supports effectively-once) for a Go function; strict-delivery requirements copied into Go-based deployments; CI templates that set EFFECTIVELY_ONCE globally.

Related errors


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