{"record":{"id":"2f4943866dcdd30b","repo":"apache/pulsar","slug":"sink-class-s-not-found","errorCode":null,"errorMessage":"Sink class %s not found","messagePattern":"Sink class (.+?) not found","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java","lineNumber":478,"sourceCode":"        // thus we should try to find it class name in the NAR service definition\n        if (sinkClassName == null) {\n            ConnectorDefinition connectorDefinition = sinkFunction.getFunctionMetaData(ConnectorDefinition.class);\n            if (connectorDefinition == null) {\n                throw new IllegalArgumentException(\n                        \"Sink package doesn't contain the META-INF/services/pulsar-io.yaml file.\");\n            }\n            sinkClassName = connectorDefinition.getSinkClass();\n            if (sinkClassName == null) {\n                throw new IllegalArgumentException(\"Failed to extract sink class from archive\");\n            }\n        }\n\n        // check if sink implements the correct interfaces\n        TypeDefinition sinkClass;\n        try {\n            sinkClass = sinkFunction.resolveType(sinkClassName);\n        } catch (TypePool.Resolution.NoSuchTypeException e) {\n            throw new IllegalArgumentException(\n                    String.format(\"Sink class %s not found\", sinkClassName), e);\n        }\n\n        String functionClassName = sinkConfig.getTransformFunctionClassName();\n        TypeDefinition typeArg;\n        ValidatableFunctionPackage inputFunction;\n        if (transformFunction != null) {\n            // if function class name in sink config is not set, this should be a built-in function\n            // thus we should try to find it class name in the NAR service definition\n            if (functionClassName == null) {\n                FunctionDefinition functionDefinition =\n                        transformFunction.getFunctionMetaData(FunctionDefinition.class);\n                if (functionDefinition == null) {\n                    throw new IllegalArgumentException(\n                            \"Function package doesn't contain the META-INF/services/pulsar-io.yaml file.\");\n                }\n                functionClassName = functionDefinition.getFunctionClass();\n                if (functionClassName == null) {","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java#L460-L496","documentation":"Thrown by SinkConfigUtils.validateAndExtractDetails when the sink's class name (sinkClassName) cannot be resolved in the sink package's type pool via ByteBuddy's resolveType. The library validates that the configured sink class exists in the uploaded archive/NAR before creating a sink. It wraps TypePool.Resolution.NoSuchTypeException in an IllegalArgumentException.","triggerScenarios":"Creating/updating a sink whose className does not match any class inside the provided archive or built-in connector NAR; typo in the fully-qualified class name; the class is in the NAR but not visible to the functions worker's classloader.","commonSituations":"Typos in sinkConfig className; deploying a connector NAR built with a shaded/renamed class; uploading a custom jar missing the sink class; class name changed after a connector upgrade.","solutions":["Verify the className in sinkConfig matches the fully-qualified name of a class implementing org.apache.pulsar.io.core.Sink in the archive","Run `jar tf <archive>` (or inspect the NAR) to confirm the class file exists at the expected path","Rebuild/re-upload the connector NAR or function package so it contains the sink class","Confirm the connector is installed in the functions worker's connectors directory if using a built-in connector"],"exampleFix":"// before\nsinkConfig.setClassName(\"org.example.MySinkt\");\n// after\nsinkConfig.setClassName(\"org.example.MySink\");","handlingStrategy":"validation","validationCode":"try (Closer c = Closer.create()) {\n  // verify class exists in the archive before submitting\n  try (java.util.jar.JarFile jar = new java.util.jar.JarFile(archivePath)) {\n    String entry = sinkClassName.replace('.', '/') + \".class\";\n    if (jar.getJarEntry(entry) == null) {\n      throw new IllegalStateException(\"Sink class \" + sinkClassName + \" not in archive\");\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  admin.sinks().createSink(config, archivePath);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"not found\") && e.getMessage().startsWith(\"Sink class\")) {\n    log.error(\"Fix sinkConfig.className; class not present in uploaded archive\", e);\n  } else { throw e; }\n}","preventionTips":["Copy the fully-qualified class name from the connector's docs/source instead of typing it","Verify with `jar tf archive.jar | grep Sink` before submitting","After connector upgrades, re-check class names for renames"],"tags":["pulsar-functions","sink","classpath","configuration"],"backgroundTag":"class-not-found","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"}