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.
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
- Sink class does not implement the correct interface
- SourceRecord class type must be PulsarRecord
- Cannot find/load class
- Component cannot get state store
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/e6bb25b977e12ec1.
Report an issue: GitHub.
Appendix: 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)