apache/pulsar · error · IOException

Class ${handlerClass} does not implement protocol handler in

Error message

Class ${handlerClass} does not implement protocol handler interface

What it means

Thrown by ProtocolHandlerUtils.load after the handler class is instantiated but the resulting object is not an instance of ProtocolHandler. The NAR declared a handlerClass, but that class does not implement the required interface, so the broker rejects it.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/protocol/ProtocolHandlerUtils.java:140

                                               String narExtractionDirectory) throws IOException {
        final File narFile = metadata.getArchivePath().toAbsolutePath().normalize().toFile();
        NarClassLoader ncl = NarClassLoaderBuilder.builder()
                .narFile(narFile)
                .parentClassLoader(ProtocolHandler.class.getClassLoader())
                .extractionDirectory(narExtractionDirectory)
                .build();

        ProtocolHandlerDefinition phDef = getProtocolHandlerDefinition(ncl);
        if (StringUtils.isBlank(phDef.getHandlerClass())) {
            throw new IOException("Protocol handler `" + phDef.getName() + "` does NOT provide a protocol"
                + " handler implementation");
        }

        try {
            Class handlerClass = ncl.loadClass(phDef.getHandlerClass());
            Object handler = handlerClass.getDeclaredConstructor().newInstance();
            if (!(handler instanceof ProtocolHandler)) {
                throw new IOException("Class " + phDef.getHandlerClass()
                    + " does not implement protocol handler interface");
            }
            ProtocolHandler ph = (ProtocolHandler) handler;
            return new ProtocolHandlerWithClassLoader(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

  1. Make the declared handlerClass implement org.apache.pulsar.broker.protocol.ProtocolHandler and rebuild the NAR.
  2. Ensure the handler implements the ProtocolHandler interface from the SAME Pulsar version as the broker (compile against matching pulsar-broker/pulsar-common versions).
  3. Check that the handlerClass in the NAR definition points at the handler class, not a supporting class.
  4. Avoid shading conflicting copies of the ProtocolHandler interface into your NAR.

Example fix

// before
public class KafkaProtocolHandler { /* no interface */ }
// after
public class KafkaProtocolHandler implements ProtocolHandler {
  public void initialize(ProtocolHandlerData ... ) { ... }
  ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the class implements ProtocolHandler before packaging
class Check {
  public static void main(String[] a) throws Exception {
    Class<?> c = Class.forName(a[0]);
    if (!org.apache.pulsar.broker.protocol.ProtocolHandler.class.isAssignableFrom(c))
      throw new IllegalStateException(a[0] + " does not implement ProtocolHandler");
  }
}

Try / catch

try {
  handler = ProtocolHandlerUtils.load(definition, narDir);
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("does not implement protocol handler interface")) {
    log.error("Declared handlerClass must implement ProtocolHandler");
  }
  throw e;
}

Prevention

When it happens

Trigger: ProtocolHandlerUtils.load loads phDef.getHandlerClass() and calls newInstance(); the created object fails the `instanceof ProtocolHandler` check.

Common situations: Pointing handlerClass at a helper/config class instead of the handler; a class implementing a ProtocolHandler from an incompatible Pulsar version loaded on a different classloader; refactoring renamed/moved the interface so the class no longer implements it.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/4478284cdb984150. Report an issue: GitHub.