{"record":{"id":"04c57610c1d81e60","repo":"apache/pulsar","slug":"class-sinkclass-does-not-implement-interface-or","errorCode":null,"errorMessage":"Class ${sinkClass} does not implement interface org.apache.pulsar.functions.api.Sink","messagePattern":"Class (.+?) does not implement interface org\\.apache\\.pulsar\\.functions\\.api\\.Sink","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/io/ConnectorUtils.java","lineNumber":103,"sourceCode":"\n        return conf.getSourceClass();\n    }\n\n    /**\n     * Extract the Pulsar IO Sink class from a connector archive.\n     */\n    public static String getIOSinkClass(NarClassLoader narClassLoader) throws IOException {\n        ConnectorDefinition conf = getConnectorDefinition(narClassLoader);\n        if (StringUtils.isEmpty(conf.getSinkClass())) {\n            throw new IOException(\n                    String.format(\"The '%s' connector does not provide a sink implementation\", conf.getName()));\n        }\n\n        try {\n            // Try to load sink class and check it implements Sink interface\n            Class<?> sinkClass = narClassLoader.loadClass(conf.getSinkClass());\n            if (!(Sink.class.isAssignableFrom(sinkClass))) {\n                throw new IOException(\n                        \"Class \" + conf.getSinkClass() + \" does not implement interface \" + Sink.class.getName());\n            }\n        } catch (Throwable t) {\n            Exceptions.rethrowIOException(t);\n        }\n\n        return conf.getSinkClass();\n    }\n\n    public static ConnectorDefinition getConnectorDefinition(File narFile) throws IOException {\n        return FunctionUtils.getPulsarIOServiceConfig(narFile, ConnectorDefinition.class);\n    }\n\n    public static ConnectorDefinition getConnectorDefinition(NarClassLoader narClassLoader) throws IOException {\n        return FunctionUtils.getPulsarIOServiceConfig(narClassLoader, ConnectorDefinition.class);\n    }\n\n    public static List<ConfigFieldDefinition> getConnectorConfigDefinition(","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/io/ConnectorUtils.java#L85-L121","documentation":"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.","triggerScenarios":"Calling getIOSinkClass(narClassLoader) where the metadata's sinkClass resolves to a class that does not implement Sink.","commonSituations":"sinkClass pointing at a Source or plain class; copy-paste of sourceClass into sinkClass; interface dropped during a connector upgrade/refactor.","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"],"exampleFix":"// before\nsinkClass=com.example.MyHelper  // not a Sink\n// after\nsinkClass=com.example.MySink  // implements org.apache.pulsar.functions.api.Sink","handlingStrategy":"validation","validationCode":"String cls = ConnectorUtils.getConnectorDefinition(loader).getSinkClass();\nClass<?> c = Class.forName(cls, false, loader);\nif (!Sink.class.isAssignableFrom(c)) {\n    throw new IllegalArgumentException(cls + \" is not a Sink\");\n}","typeGuard":"boolean isValidSinkClass(String name, NarClassLoader loader) throws ClassNotFoundException {\n    return Sink.class.isAssignableFrom(loader.loadClass(name));\n}","tryCatchPattern":"try {\n    String sink = ConnectorUtils.getIOSinkClass(loader);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"does not implement interface\")) {\n        // fail fast: connector metadata points at a non-Sink class\n    } else { throw e; }\n}","preventionTips":["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"],"tags":["pulsar-io","connector","type-mismatch","sink"],"backgroundTag":"class-does-not-implement-interface","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}