apache/pulsar · error · RuntimeException
Sink does not implement correct interface
Error message
Sink does not implement correct interface
What it means
Symmetric to the Source check: when setting up a Sink component, JavaInstanceRunnable verifies the loaded object implements org.apache.pulsar.functions.api.Sink and throws RuntimeException if not. The sink's type argument (sinkTypeArg) is resolved via TypeResolver only after this check passes.
Source
Thrown at pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/JavaInstanceRunnable.java:1146
conf.hasBatchingSpec() ? conf.getBatchingSpec() : null))
.compressionType(FunctionCommon.convertFromFunctionDetailsCompressionType(
conf.getCompressionType()));
pulsarSinkConfig.setProducerConfig(builder.build());
object = new PulsarSink(this.client, pulsarSinkConfig, this.properties, this.stats,
this.functionClassLoader, this.producerCache);
}
} else {
object = Reflections.createInstance(
sinkSpec.getClassName(),
this.componentClassLoader);
}
if (object instanceof Sink) {
this.sink = (Sink) object;
this.sinkTypeArg = TypeResolver.resolveRawArguments(Sink.class, object.getClass())[0];
} else {
throw new RuntimeException("Sink does not implement correct interface");
}
if (componentType == FunctionDetails.ComponentType.SINK) {
Thread.currentThread().setContextClassLoader(this.componentClassLoader);
}
try {
log.debug()
.attr("sinkConfig", sinkSpec.getConfigs())
.attr("contextImpl", contextImpl.toString())
.log("Opening Sink");
this.sink.open(augmentAndFilterConnectorConfig(sinkSpec.getConfigs()), contextImpl);
} catch (Exception e) {
log.error().exception(e).log("Sink open produced uncaught exception");
throw e;
} finally {
Thread.currentThread().setContextClassLoader(this.instanceClassLoader);
}
}View on GitHub (pinned to 820761864e)
Solutions
- Verify the configured className implements org.apache.pulsar.functions.api.Sink
- Set pulsar-functions-api to provided scope so the interface is not duplicated inside the function JAR
- Confirm the FunctionDetails componentType is SINK; redeploy with the correct component type
- Clear the worker's functions extraction directory and restart workers to purge stale classloader state
Example fix
// before
functions:
- className: com.acme.MyProcessor # a Function, not a Sink
componentType: SINK
// after
functions:
- className: com.acme.MySink
componentType: SINK Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName(className);
if (!Sink.class.isAssignableFrom(c)) {
throw new IllegalArgumentException(className + " does not implement Sink");
} Type guard
boolean isSink(Object o) { return o instanceof Sink; } Try / catch
try { setupSink(); }
catch (RuntimeException e) {
if (e.getMessage().contains("Sink does not implement correct interface")) {
log.error("Wrong class or duplicated Sink interface in classpath", e);
}
} Prevention
- Set pulsar-functions-api to provided scope in sink builds
- Confirm componentType SINK matches a class implementing Sink
- Purge worker function-extraction directories after JAR updates
- Deploy sinks with an explicit, reviewed deployment manifest
When it happens
Trigger: A Function or Source class is configured as a Sink component; the Sink interface was bundled twice in the classpath so instanceof fails across classloaders; className points to the wrong class.
Common situations: Redeploying an existing function as a sink without changing className; uber JAR containing pulsar-functions-api classes; stale worker-side extracted JARs after a JAR update; copy-pasted deployment manifest with wrong component type.
Related errors
- Source does not implement correct interface
- SourceRecord class type must be PulsarRecord
- Sink class %s does not implement the correct interface
- Field '${name}' with value '${o}' does not implement ${class
- Cannot find/load class ${className}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/e6bb25b977e12ec1.
Report an issue: GitHub.