{"record":{"id":"793758a24e2d4eea","repo":"apache/pulsar","slug":"function-package-doesn-t-contain-the-meta-inf-serv","errorCode":null,"errorMessage":"Function package doesn't contain the META-INF/services/pulsar-io.yaml file.","messagePattern":"Function package doesn't contain the META-INF/services/pulsar-io\\.yaml file\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java","lineNumber":492,"sourceCode":"        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) {\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            }","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java#L474-L510","documentation":"Thrown when a sink config sets no transformFunctionClassName, so the library treats the uploaded package as a transform-function package and looks up its service definition via META-INF/services/pulsar-io.yaml. If FunctionMetaData is null the package is not a valid transform function package.","triggerScenarios":"Passing a function/transform package (or arbitrary jar) as sinkFunction while sinkConfig.getTransformFunctionClassName() is null and the archive lacks META-INF/services/pulsar-io.yaml.","commonSituations":"Using a plain sink jar where a transform-function package is expected; building a NAR without the service descriptor file; wrong file placed in the service directory.","solutions":["Add META-INF/services/pulsar-io.yaml declaring the FunctionDefinition (name, functionClass, type args) inside the package","Or set sinkConfig.setTransformFunctionClassName(...) explicitly so the service lookup path is skipped","Verify you uploaded the intended transform-function archive, not a plain sink jar"],"exampleFix":"// before\n// jar has no META-INF/services/pulsar-io.yaml, transformFunctionClassName unset\nsinkConfig.setTransformFunctionClassName(null);\n// after\nsinkConfig.setTransformFunctionClassName(\"org.example.MyTransformFunction\");","handlingStrategy":"validation","validationCode":"try (java.util.jar.JarFile jar = new java.util.jar.JarFile(pkgPath)) {\n  if (jar.getJarEntry(\"META-INF/services/pulsar-io.yaml\") == null\n      && sinkConfig.getTransformFunctionClassName() == null) {\n    throw new IllegalStateException(\"Package is not a transform function package and no transformFunctionClassName set\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  admin.sinks().createSink(config, pkgPath);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"pulsar-io.yaml\")) {\n    log.error(\"Set transformFunctionClassName or fix the package's service descriptor\", e);\n  } else { throw e; }\n}","preventionTips":["Ensure build includes resources: check pulsar-io.yaml lands in META-INF/services in the artifact","Only pass transform-function archives where the pipeline expects them","Set transformFunctionClassName explicitly when in doubt"],"tags":["pulsar-functions","sink","service-loader","packaging"],"backgroundTag":"missing-service-descriptor","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}