apache/pulsar · critical · IOException
Class ${handlerClass} does not implement worker service inte
Error message
Class ${handlerClass} does not implement worker service interface What it means
WorkerServiceLoader.load() instantiates the handler class declared in the NAR's WorkerServiceDefinition. If the instantiated object does not implement the org.apache.pulsar.functions.worker.service.WorkerService interface, loading fails with this IOException. The NAR metadata exists but points at a class with the wrong type.
Source
Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/service/WorkerServiceLoader.java:93
String narExtractionDirectory) throws IOException {
final File narFile = metadata.getArchivePath().toAbsolutePath().normalize().toFile();
NarClassLoader ncl = NarClassLoaderBuilder.builder()
.narFile(narFile)
.parentClassLoader(WorkerService.class.getClassLoader())
.extractionDirectory(narExtractionDirectory)
.build();
WorkerServiceDefinition phDef = getWorkerServiceDefinition(ncl);
if (StringUtils.isBlank(phDef.getHandlerClass())) {
throw new IOException("Functions Worker Service Nar Package `" + phDef.getName()
+ "` does NOT provide a functions worker service implementation");
}
try {
Class<?> handlerClass = ncl.loadClass(phDef.getHandlerClass());
Object handler = handlerClass.getDeclaredConstructor().newInstance();
if (!(handler instanceof WorkerService)) {
throw new IOException("Class " + phDef.getHandlerClass()
+ " does not implement worker service interface");
}
WorkerService ph = (WorkerService) handler;
return new WorkerServiceWithClassLoader(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 declared handler class implement org.apache.pulsar.functions.worker.service.WorkerService
- Fix the handlerClass entry in the NAR's WorkerServiceDefinition to point at the correct class
- Rebuild the NAR against the same Pulsar version as the broker so the WorkerService interface matches
Example fix
// before
public class MyWorker { /* no WorkerService */ }
// after
public class MyWorker implements WorkerService {
@Override public void initialize(WorkerConfig config, AuthenticationProtocol auth) { ... }
@Override public void start() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// confirm the handler class in the NAR implements WorkerService before deployment
classpath-load handlerClass;
if (!WorkerService.class.isInstance(instantiated)) throw new IllegalStateException("handlerClass is not a WorkerService"); Prevention
- Ensure custom NAR handler classes implement WorkerService
- Rebuild custom worker NARs against the same Pulsar version as the broker
- Validate handlerClass entries in WorkerServiceDefinition metadata in CI
- Smoke-test the NAR with a standalone worker before production rollout
When it happens
Trigger: A NAR whose WorkerServiceDefinition.handlerClass names a class that exists and instantiates but is not a WorkerService (custom fork drift, wrong class name in metadata, or a re-implemented handler after an interface rename).
Common situations: Building a custom worker NAR against an incompatible Pulsar API version where WorkerService changed; typos or copy-paste errors in the handlerClass metadata entry; refactoring a handler class without updating its implemented interface.
Related errors
- Functions Worker Service Nar Package `${name}` does NOT prov
- No offloader found for driver '${driverName}'. Please make s
- Could not open configuration file
- Malformed configuration file
- Need to specify a configuration file for broker
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/83b3d532a3036d28.
Report an issue: GitHub.