{"record":{"id":"52704e31aeb8e445","repo":"apache/pulsar","slug":"class-extensionclass-does-not-implement-extensi","errorCode":null,"errorMessage":"Class ${extensionClass} does not implement extension interface","messagePattern":"Class (.+?) does not implement extension interface","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-proxy/src/main/java/org/apache/pulsar/proxy/extensions/ProxyExtensionsUtils.java","lineNumber":142,"sourceCode":"                                              String narExtractionDirectory) throws IOException {\n        final File narFile = metadata.getArchivePath().toAbsolutePath().normalize().toFile();\n        NarClassLoader ncl = NarClassLoaderBuilder.builder()\n                .narFile(narFile)\n                .parentClassLoader(ProxyExtension.class.getClassLoader())\n                .extractionDirectory(narExtractionDirectory)\n                .build();\n\n        ProxyExtensionDefinition phDef = getProxyExtensionDefinition(ncl);\n        if (StringUtils.isBlank(phDef.getExtensionClass())) {\n            throw new IOException(\"extension `\" + phDef.getName() + \"` does NOT provide a protocol\"\n                + \" handler implementation\");\n        }\n\n        try {\n            Class<?> extensionClass = ncl.loadClass(phDef.getExtensionClass());\n            Object extension = extensionClass.getDeclaredConstructor().newInstance();\n            if (!(extension instanceof ProxyExtension)) {\n                throw new IOException(\"Class \" + phDef.getExtensionClass()\n                    + \" does not implement extension interface\");\n            }\n            ProxyExtension ph = (ProxyExtension) extension;\n            return new ProxyExtensionWithClassLoader(ph, ncl);\n        } catch (Throwable t) {\n            rethrowIOException(t);\n            return null;\n        }\n    }\n\n    private static void rethrowIOException(Throwable cause)\n            throws IOException {\n        if (cause instanceof IOException) {\n            throw (IOException) cause;\n        } else if (cause instanceof RuntimeException) {\n            throw (RuntimeException) cause;\n        } else if (cause instanceof Error) {\n            throw (Error) cause;","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/extensions/ProxyExtensionsUtils.java#L124-L160","documentation":"Thrown when the class named in the NAR's extensionClass descriptor is loaded and instantiated but is not an instance of ProxyExtension. The descriptor exists, yet points at the wrong class — often an implementation of a different interface or a support class.","triggerScenarios":"ProxyExtensionsUtils.load loading a NAR whose extensionClass names a class that does not implement org.apache.pulsar.proxy.extensions.ProxyExtension (or was compiled against a Pulsar version where the interface changed/moved).","commonSituations":"Copy-pasting an old example class that implements a deprecated API; building the extension against mismatched Pulsar client/proxy dependency versions; pointing extensionClass at a factory or config class by mistake.","solutions":["Make the configured class implement org.apache.pulsar.proxy.extensions.ProxyExtension (or change extensionClass to one that does)","Rebuild the NAR against the same Pulsar version as the running proxy so the interface matches","Verify the class with 'javap -classpath ... <class>' to confirm it implements ProxyExtension","Check the extension's changelog for interface migrations when upgrading Pulsar"],"exampleFix":"// before\npublic class MyExtension { public void init(...) {} }\n// after\npublic class MyExtension implements ProxyExtension {\n  @Override public boolean accept(String extension) { return \"myext\".equals(extension); }\n  // ...\n}","handlingStrategy":"validation","validationCode":"// Compile-time check in the extension project\nClass<?> c = Class.forName(\"org.example.MyProxyExtension\");\nif (!ProxyExtension.class.isAssignableFrom(c))\n    throw new IllegalStateException(\"extensionClass must implement ProxyExtension\");","typeGuard":"// Java instanceof narrowing\nObject o = extensionClass.getDeclaredConstructor().newInstance();\nif (o instanceof ProxyExtension) {\n    ProxyExtension ext = (ProxyExtension) o; // safe\n}","tryCatchPattern":"try { proxyExtensions.load(conf); } catch (RuntimeException e) { if (e.getMessage().contains(\"does not implement extension interface\")) log.error(\"extensionClass points at a non-ProxyExtension class\"); throw e; }","preventionTips":["Have the extension class implement ProxyExtension explicitly in its signature","Build the extension against the exact Pulsar version of the running proxy"],"tags":["pulsar-proxy","extensions","class-loading"],"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"}