{"record":{"id":"941de66fa8008a45","repo":"apache/pulsar","slug":"function-class-s-not-found","errorCode":null,"errorMessage":"Function class %s not found","messagePattern":"Function 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":504,"sourceCode":"            // 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) {\n                    throw new IllegalArgumentException(\"Transform function class name must be set\");\n                }\n            }\n            TypeDefinition functionClass;\n            try {\n                functionClass = transformFunction.resolveType(functionClassName);\n            } catch (TypePool.Resolution.NoSuchTypeException e) {\n                throw new IllegalArgumentException(\n                        String.format(\"Function class %s not found\", functionClassName), e);\n            }\n            // extract type from transform function class\n            if (!getRawFunctionTypes(functionClass, false)[1].asErasure().isAssignableTo(Record.class)) {\n                throw new IllegalArgumentException(\"Sink transform function output must be of type Record\");\n            }\n            typeArg = getFunctionTypes(functionClass, false)[0];\n            inputFunction = transformFunction;\n        } else {\n            // extract type from sink class\n            typeArg = getSinkType(sinkClass);\n            inputFunction = sinkFunction;\n        }\n\n        if (sinkConfig.getTopicToSerdeClassName() != null) {\n            for (String serdeClassName : sinkConfig.getTopicToSerdeClassName().values()) {\n                ValidatorUtils.validateSerde(serdeClassName, typeArg, inputFunction.getTypePool(), true);\n            }","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java#L486-L522","documentation":"Thrown when the transform function class name resolved from config/service descriptor cannot be found in the transform function package's type pool. Mirrors error 1470 but for the transform function class of a sink with a transform stage.","triggerScenarios":"sinkConfig.transformFunctionClassName (or the value from pulsar-io.yaml) names a class absent from the uploaded transform function archive.","commonSituations":"Typos in the function class name; class renamed/refactored between versions; package uploaded is stale relative to the config.","solutions":["Check that transformFunctionClassName matches a class in the uploaded archive (`jar tf`)","Re-upload a package containing the transform function class","Fix the functionClass entry in META-INF/services/pulsar-io.yaml if that is the source of the name"],"exampleFix":"// before\nsinkConfig.setTransformFunctionClassName(\"org.example.OldTransform\");\n// after\nsinkConfig.setTransformFunctionClassName(\"org.example.NewTransform\");","handlingStrategy":"validation","validationCode":"try (java.util.jar.JarFile jar = new java.util.jar.JarFile(pkgPath)) {\n  String entry = transformClassName.replace('.', '/') + \".class\";\n  if (jar.getJarEntry(entry) == null) {\n    throw new IllegalStateException(\"Transform class \" + transformClassName + \" not in package\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  admin.sinks().createSink(config, pkgPath);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Function class\")) {\n    log.error(\"transformFunctionClassName not found in package; align config with artifact\", e);\n  } else { throw e; }\n}","preventionTips":["Regenerate sink configs after refactoring/renaming transform classes","Keep config class names in the same repo/build as the package","`jar tf` check in deployment scripts"],"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"}