apache/pulsar · error · IOException
Class ${extensionClass} does not implement extension interfa
Error message
Class ${extensionClass} does not implement extension interface What it means
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.
Source
Thrown at pulsar-proxy/src/main/java/org/apache/pulsar/proxy/extensions/ProxyExtensionsUtils.java:142
String narExtractionDirectory) throws IOException {
final File narFile = metadata.getArchivePath().toAbsolutePath().normalize().toFile();
NarClassLoader ncl = NarClassLoaderBuilder.builder()
.narFile(narFile)
.parentClassLoader(ProxyExtension.class.getClassLoader())
.extractionDirectory(narExtractionDirectory)
.build();
ProxyExtensionDefinition phDef = getProxyExtensionDefinition(ncl);
if (StringUtils.isBlank(phDef.getExtensionClass())) {
throw new IOException("extension `" + phDef.getName() + "` does NOT provide a protocol"
+ " handler implementation");
}
try {
Class<?> extensionClass = ncl.loadClass(phDef.getExtensionClass());
Object extension = extensionClass.getDeclaredConstructor().newInstance();
if (!(extension instanceof ProxyExtension)) {
throw new IOException("Class " + phDef.getExtensionClass()
+ " does not implement extension interface");
}
ProxyExtension ph = (ProxyExtension) extension;
return new ProxyExtensionWithClassLoader(ph, ncl);
} catch (Throwable t) {
rethrowIOException(t);
return null;
}
}
private static void rethrowIOException(Throwable cause)
throws IOException {
if (cause instanceof IOException) {
throw (IOException) cause;
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;View on GitHub (pinned to 820761864e)
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
Example fix
// before
public class MyExtension { public void init(...) {} }
// after
public class MyExtension implements ProxyExtension {
@Override public boolean accept(String extension) { return "myext".equals(extension); }
// ...
} Defensive patterns
Strategy: validation
Validate before calling
// Compile-time check in the extension project
Class<?> c = Class.forName("org.example.MyProxyExtension");
if (!ProxyExtension.class.isAssignableFrom(c))
throw new IllegalStateException("extensionClass must implement ProxyExtension"); Type guard
// Java instanceof narrowing
Object o = extensionClass.getDeclaredConstructor().newInstance();
if (o instanceof ProxyExtension) {
ProxyExtension ext = (ProxyExtension) o; // safe
} Try / catch
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; } Prevention
- Have the extension class implement ProxyExtension explicitly in its signature
- Build the extension against the exact Pulsar version of the running proxy
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Failed to load the extension for extension name `${extension
- Malformed extension found for extension name `${extensionNam
- extension for `${extensionName}` attempts to use ${address}
- extension `${name}` does NOT provide a protocol handler impl
- Failed to bind extension `${extensionName}` on ${address}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/52704e31aeb8e445.
Report an issue: GitHub.