apache/pulsar · error · IOException
Class ${sinkClass} does not implement interface org.apache.p
Error message
Class ${sinkClass} does not implement interface org.apache.pulsar.functions.api.Sink What it means
getIOSinkClass loads the declared sinkClass from the connector NAR and verifies it implements org.apache.pulsar.functions.api.Sink. If it does not, an IOException is thrown since the class is not a valid Pulsar IO sink.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/io/ConnectorUtils.java:103
return conf.getSourceClass();
}
/**
* Extract the Pulsar IO Sink class from a connector archive.
*/
public static String getIOSinkClass(NarClassLoader narClassLoader) throws IOException {
ConnectorDefinition conf = getConnectorDefinition(narClassLoader);
if (StringUtils.isEmpty(conf.getSinkClass())) {
throw new IOException(
String.format("The '%s' connector does not provide a sink implementation", conf.getName()));
}
try {
// Try to load sink class and check it implements Sink interface
Class<?> sinkClass = narClassLoader.loadClass(conf.getSinkClass());
if (!(Sink.class.isAssignableFrom(sinkClass))) {
throw new IOException(
"Class " + conf.getSinkClass() + " does not implement interface " + Sink.class.getName());
}
} catch (Throwable t) {
Exceptions.rethrowIOException(t);
}
return conf.getSinkClass();
}
public static ConnectorDefinition getConnectorDefinition(File narFile) throws IOException {
return FunctionUtils.getPulsarIOServiceConfig(narFile, ConnectorDefinition.class);
}
public static ConnectorDefinition getConnectorDefinition(NarClassLoader narClassLoader) throws IOException {
return FunctionUtils.getPulsarIOServiceConfig(narClassLoader, ConnectorDefinition.class);
}
public static List<ConfigFieldDefinition> getConnectorConfigDefinition(View on GitHub (pinned to 820761864e)
Solutions
- Point sinkClass at a class implementing org.apache.pulsar.functions.api.Sink and rebuild the NAR
- Ensure the correct (not duplicated) class name is in the connector metadata
- Verify interface compatibility between the connector's pulsar-io-core version and the runtime
Example fix
// before sinkClass=com.example.MyHelper // not a Sink // after sinkClass=com.example.MySink // implements org.apache.pulsar.functions.api.Sink
Defensive patterns
Strategy: validation
Validate before calling
String cls = ConnectorUtils.getConnectorDefinition(loader).getSinkClass();
Class<?> c = Class.forName(cls, false, loader);
if (!Sink.class.isAssignableFrom(c)) {
throw new IllegalArgumentException(cls + " is not a Sink");
} Type guard
boolean isValidSinkClass(String name, NarClassLoader loader) throws ClassNotFoundException {
return Sink.class.isAssignableFrom(loader.loadClass(name));
} Try / catch
try {
String sink = ConnectorUtils.getIOSinkClass(loader);
} catch (IOException e) {
if (e.getMessage().contains("does not implement interface")) {
// fail fast: connector metadata points at a non-Sink class
} else { throw e; }
} Prevention
- Verify sinkClass is distinct from sourceClass in connector metadata
- CI-check every connector NAR loads and its classes implement the right interfaces
- Keep connector implementations on one pulsar-io-core version
When it happens
Trigger: Calling getIOSinkClass(narClassLoader) where the metadata's sinkClass resolves to a class that does not implement Sink.
Common situations: sinkClass pointing at a Source or plain class; copy-paste of sourceClass into sinkClass; interface dropped during a connector upgrade/refactor.
Related errors
- Class %s does not implement interface %s or %s
- Invalid sink type '%s' -- Available sinks are: %s
- Sink package doesn't contain the META-INF/services/pulsar-io
- Failed to extract sink class from archive
- Sink transform function output must be of type Record
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/04c57610c1d81e60.
Report an issue: GitHub.