apache/pulsar · critical · RuntimeException
User class must either be Function or java.util.Function
Error message
User class must either be Function or java.util.Function
What it means
During JavaInstanceRunnable.setup, the user's class is instantiated and validated: the object must implement org.apache.pulsar.functions.api.Function (or the older WindowFunction path) or java.util.function.Function. If neither interface is implemented, a RuntimeException is thrown because the instance has no callable function interface to invoke. This catches the common mistake of loading a class that isn't actually a function.
Source
Thrown at pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/JavaInstanceRunnable.java:265
.attr("function", instanceConfig.getFunctionDetails().getName())
.attr("details", instanceConfig.getFunctionDetails())
.log("Starting Java Instance");
Object object;
if (instanceConfig.getFunctionDetails().getClassName()
.equals(org.apache.pulsar.functions.windowing.WindowFunctionExecutor.class.getName())) {
object = Reflections.createInstance(
instanceConfig.getFunctionDetails().getClassName(),
instanceClassLoader);
} else {
object = Reflections.createInstance(
instanceConfig.getFunctionDetails().getClassName(),
functionClassLoader);
}
if (!(object instanceof Function) && !(object instanceof java.util.function.Function)) {
throw new RuntimeException("User class must either be Function or java.util.Function");
}
// start the state table
setupStateStore();
ContextImpl contextImpl = setupContext();
// start the output producer
setupOutput(contextImpl);
// start the input consumer
setupInput(contextImpl);
// start any log topic handler
setupLogHandler();
if (!(object instanceof IdentityFunction) && !(sink instanceof PulsarSink)) {
sinkSchemaInfoProvider = new SinkSchemaInfoProvider();
}
View on GitHub (pinned to 820761864e)
Solutions
- Make the user class implement org.apache.pulsar.functions.api.Function<I,O> (or java.util.function.Function) and redeploy.
- Verify the function's className setting points at the correct fully-qualified class in the uploaded jar.
- Check the function's jar/classloader contains the right version of the class (no stale jars).
Example fix
// before
public class MyProcessor {
public String process(String input) { return input.toUpperCase(); }
}
// after
public class MyProcessor implements Function<String, String> {
@Override
public String process(String input, Context context) { return input.toUpperCase(); }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = functionClassLoader.loadClass(className);
if (!org.apache.pulsar.functions.api.Function.class.isAssignableFrom(c)
&& !java.util.function.Function.class.isAssignableFrom(c)) {
throw new IllegalArgumentException(className + " must implement Function or java.util.function.Function");
} Type guard
boolean isUserFunction(Object o) {
return o instanceof org.apache.pulsar.functions.api.Function
|| o instanceof java.util.function.Function;
} Try / catch
try { new JavaInstanceRunnable(...); } catch (RuntimeException e) { if (e.getMessage().startsWith("User class must")) { throw new IllegalStateException("Fix function className or implement Function", e); } throw e; } Prevention
- Verify className points to a class implementing Function/java.util.function.Function
- Smoke-test the jar locally before deploying the function
- Avoid duplicate class versions across function jars
- Use pulsar-admin functions create validation output to catch bad classNames early
When it happens
Trigger: Deploying a function whose className points to a class that implements neither pulsar Function nor java.util.function.Function — e.g. a helper class, a class implementing only the deprecated deprecated Function variants, or a wrong class name resolving to a different type in the specified classloader.
Common situations: Typo/wrong value in the function's className config; jar containing multiple versions of the class; upgrading code where the function no longer implements the API; using Scala/Groovy lambdas or classes that implement similar but distinct interfaces.
Related errors
- Unknown component type: %s
- Access to environment variable %s is not allowed.
- PulsarAdmin is not enabled in function worker
- Getting consumer is not supported
- Not support component type
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/ef525596a7dd305b.
Report an issue: GitHub.