{"record":{"id":"7d9a93754f99c072","repo":"apache/pulsar","slug":"failed-to-extract-s-class-from-archive","errorCode":null,"errorMessage":"Failed to extract %s class from archive","messagePattern":"Failed to extract (.+?) class from archive","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionRuntimeCommon.java","lineNumber":92,"sourceCode":"            if (isEmpty(connectorClassName)) {\n                if (narClassLoader == null) {\n                    throw new IllegalArgumentException(String.format(\"%s package does not have the correct format. \"\n                                    + \"Pulsar cannot determine if the package is a NAR package or JAR package. \"\n                                    + \"%s classname is not provided and attempts to load it as a NAR package produced \"\n                                    + \"the following error.\",\n                            FunctionCommon.capFirstLetter(componentType), FunctionCommon.capFirstLetter(componentType)),\n                            narClassLoaderException);\n                }\n                try {\n                    if (componentType == FunctionDetails.ComponentType.FUNCTION) {\n                        connectorClassName = FunctionUtils.getFunctionClass(narClassLoader);\n                    } else if (componentType == FunctionDetails.ComponentType.SOURCE) {\n                        connectorClassName = ConnectorUtils.getIOSourceClass(narClassLoader);\n                    } else {\n                        connectorClassName = ConnectorUtils.getIOSinkClass(narClassLoader);\n                    }\n                } catch (IOException e) {\n                    throw new IllegalArgumentException(String.format(\"Failed to extract %s class from archive\",\n                            componentType.toString().toLowerCase()), e);\n                }\n\n                try {\n                    narClassLoader.loadClass(connectorClassName);\n                    keepNarClassLoader = true;\n                    return narClassLoader;\n                } catch (ClassNotFoundException | NoClassDefFoundError e) {\n                    throw new IllegalArgumentException(String.format(\"%s class %s must be in class path\",\n                            FunctionCommon.capFirstLetter(componentType), connectorClassName), e);\n                }\n\n            } else {\n                // if connector class name is provided, we need to try to load it as a JAR and as a NAR.\n                if (jarClassLoader != null) {\n                    try {\n                        jarClassLoader.loadClass(connectorClassName);\n                        keepJarClassLoader = true;","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionRuntimeCommon.java#L74-L110","documentation":"Thrown by getClassLoaderFromPackage when a NAR archive is being registered as a Pulsar IO connector source/sink. After loading the NAR, the code calls ConnectorUtils.getIOSourceClass/getIOSinkClass, which reads the connector metadata; if that I/O fails, the code wraps the IOException in an IllegalArgumentException naming the component type (source/sink).","triggerScenarios":"Registering/updating a source or sink function whose archive is a NAR package; ConnectorUtils.getIOSourceClass or getIOSinkClass throws IOException while reading the NAR's META-INF/services connector descriptor (missing, unreadable, or malformed descriptor inside the archive).","commonSituations":"A NAR built without the META-INF/services/org.apache.pulsar.io.spi.Loadable file; archive corrupted during upload; the NAR was built for a different Pulsar IO SPI version so the descriptor cannot be read.","solutions":["Verify the NAR contains META-INF/services/org.apache.pulsar.io.spi.Loadable and that it declares a class implementing PulsarSource/PulsarSink","Rebuild the connector with a matching version of pulsar-io-core and the pulsar-io-spi dependencies (scope provided)","Re-upload/re-download the archive and retry registration to rule out a corrupted transfer","Unzip the NAR locally and confirm the descriptor is present and well-formed before uploading"],"exampleFix":"// before: NAR built as plain jar without IO SPI descriptor\n// pom.xml missing pulsar-io-core\n// after\n<dependency>\n  <groupId>org.apache.pulsar</groupId>\n  <artifactId>pulsar-io-core</artifactId>\n  <version>${pulsar.version}</version>\n  <scope>provided</scope>\n</dependency>","handlingStrategy":"validation","validationCode":"try (JarFile jar = new JarFile(archivePath)) {\n  if (jar.getEntry(\"META-INF/services/org.apache.pulsar.io.spi.Loadable\") == null) {\n    throw new IllegalStateException(\"Archive is missing connector SPI descriptor\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  createFunction(...);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"Failed to extract\")) {\n    log.error(\"NAR missing/malformed connector descriptor\", e);\n  }\n}","preventionTips":["Always build NARs with the pulsar NAR packaging so META-INF/services descriptors are generated","Verify archive contents locally with 'unzip -l' before uploading","Keep pulsar-io-core at 'provided' scope so SPI versions match the broker"],"tags":["pulsar-functions","nar-archive","io-connector","classpath"],"backgroundTag":"nar-connector-descriptor-missing","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"}