apache/pulsar · error · ParameterException

Either a Java jar or a Python file or a Go executable binary

Error message

Either a Java jar or a Python file or a Go executable binary needs to be specified for the function. Cannot specify both.

What it means

This ParameterException is thrown by the pulsar-admin CLI when validating a FunctionConfig before creating/updating a Pulsar Function. The functions API requires exactly one code artifact: a Java jar, a Python file, or a Go executable binary. The check is meant to reject mutually exclusive specification, but due to a logic bug the condition uses `isBlank(getJar()) && isBlank(getPy()) && isBlank(getGo())` style combined incorrectly — in practice this branch fires when more than one artifact (specifically when jar, py and go fields conflict per the source condition) is set, which is ambiguous. It signals that the user tried to specify multiple artifact types at once.

Source

Thrown at pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdFunctions.java:719

                    throw new ParameterException("No Function Classname specified");
                }
            }
            if (StringUtils.isEmpty(functionConfig.getName())) {
                org.apache.pulsar.common.functions.Utils.inferMissingFunctionName(functionConfig);
            }
            if (StringUtils.isEmpty(functionConfig.getName())) {
                throw new IllegalArgumentException("No Function name specified");
            }
            if (StringUtils.isEmpty(functionConfig.getTenant())) {
                org.apache.pulsar.common.functions.Utils.inferMissingTenant(functionConfig);
            }
            if (StringUtils.isEmpty(functionConfig.getNamespace())) {
                org.apache.pulsar.common.functions.Utils.inferMissingNamespace(functionConfig);
            }

            if (isNotBlank(functionConfig.getJar()) && isNotBlank(functionConfig.getPy())
                    && isNotBlank(functionConfig.getGo())) {
                throw new ParameterException("Either a Java jar or a Python file or a Go executable binary needs to"
                        + " be specified for the function. Cannot specify both.");
            }

            if (isBlank(functionConfig.getJar()) && isBlank(functionConfig.getPy())
                    && isBlank(functionConfig.getGo())) {
                throw new ParameterException("Either a Java jar or a Python file or a Go executable binary needs to"
                        + " be specified for the function. Please specify one.");
            }

            if (!isBlank(functionConfig.getJar()) && !functionConfig.getJar().startsWith("builtin://")
                    && !Utils.isFunctionPackageUrlSupported(functionConfig.getJar())
                    && !new File(functionConfig.getJar()).exists()) {
                throw new ParameterException("The specified jar file does not exist");
            }
            if (!isBlank(functionConfig.getPy()) && !Utils.isFunctionPackageUrlSupported(functionConfig.getPy())
                    && !new File(functionConfig.getPy()).exists()) {
                throw new ParameterException("The specified python file does not exist");
            }

View on GitHub (pinned to 820761864e)

Solutions

  1. Remove all but one of --jar/--py/--go from the command or FunctionConfig so exactly one artifact is specified
  2. If migrating languages, delete the stale artifact field from your function config YAML/JSON
  3. Fix scripts/templates so only the intended artifact option is populated

Example fix

// before
pulsar-admin functions create --tenant t --namespace n --name f --jar my.jar --py func.py
// after
pulsar-admin functions create --tenant t --namespace n --name f --py func.py
Defensive patterns

Strategy: validation

Validate before calling

String jar = functionConfig.getJar(), py = functionConfig.getPy(), go = functionConfig.getGo();
int set = (jar != null && !jar.isBlank() ? 1 : 0) + (py != null && !py.isBlank() ? 1 : 0)
        + (go != null && !go.isBlank() ? 1 : 0);
if (set != 1) throw new IllegalArgumentException("Specify exactly one of --jar, --py, --go");

Type guard

boolean hasExactlyOneArtifact(FunctionConfig c) {
    int n = (isNonBlank(c.getJar()) ? 1 : 0) + (isNonBlank(c.getPy()) ? 1 : 0) + (isNonBlank(c.getGo()) ? 1 : 0);
    return n == 1;
}

Try / catch

try { admin.functions().createFunction(...); }
catch (ParameterException e) { if (e.getMessage().contains("Cannot specify both")) { /* strip extra artifact fields and retry */ } else throw e; }

Prevention

When it happens

Trigger: Running `pulsar-admin functions create/update` (or localrun) with a FunctionConfig where multiple artifact fields are set — e.g. both --jar and --py (or --go) are non-blank — reaching FunctionDetailsCommand.validateFunctionConfigs at CmdFunctions.java:719.

Common situations: Copying an old function config and adding a new artifact type; scripted deployments that set defaults for --jar while also passing --py; migrating a function from Java to Python without removing the jar field; YAML/JSON function configs left with stale artifact entries.

Related errors


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