apache/pulsar · error · IOException

Class ${entryFilterClass} does not implement entry filter in

Error message

Class ${entryFilterClass} does not implement entry filter interface

What it means

load() instantiates the configured class via reflection and verifies it implements the EntryFilter interface before wrapping it in EntryFilterWithClassLoader. If the class instantiates but is not an EntryFilter, an IOException is thrown naming the offending class.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/service/plugin/EntryFilterProvider.java:203

    @SuppressWarnings("unchecked")
    protected EntryFilter load(EntryFilterMetaData metadata)
            throws IOException {
        final EntryFilterDefinition def = metadata.getDefinition();
        if (StringUtils.isBlank(def.getEntryFilterClass())) {
            throw new RuntimeException("Entry filter `" + def.getName() + "` does NOT provide a entry"
                    + " filters implementation");
        }
        try {
            final NarClassLoader ncl = getNarClassLoader(metadata.getArchivePath());
            if (ncl == null) {
                throw new RuntimeException("Entry filter `" + def.getName() + "` cannot be loaded, "
                        + "see the broker logs for further details");
            }
            Class entryFilterClass = ncl.loadClass(def.getEntryFilterClass());
            Object filter = entryFilterClass.getDeclaredConstructor().newInstance();
            if (!(filter instanceof EntryFilter)) {
                throw new IOException("Class " + def.getEntryFilterClass()
                        + " does not implement entry filter interface");
            }
            EntryFilter pi = (EntryFilter) filter;
            // the classloader is shared with the broker, the instance doesn't own it
            return new EntryFilterWithClassLoader(pi, ncl, false);
        } catch (Throwable e) {
            if (e instanceof IOException) {
                throw (IOException) e;
            }
            log.error()
                    .attr("entryFilterClass", metadata.getDefinition().getEntryFilterClass())
                    .exception(e)
                    .log("Failed to load class");
            throw new IOException(e);
        }
    }

    private NarClassLoader getNarClassLoader(Path archivePath) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Set entryFilterClass to a class that directly implements EntryFilter and rebuild the NAR
  2. Verify the interface package/name matches the broker's EntryFilter version
  3. Compile the filter against the same Pulsar version as the running broker

Example fix

// before
public class AuditEntryFilter { /* no interface */ }
// after
public class AuditEntryFilter implements org.apache.pulsar.broker.service.plugin.EntryFilter { ... }
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = ncl.loadClass(def.getEntryFilterClass());
if (!org.apache.pulsar.broker.service.plugin.EntryFilter.class.isAssignableFrom(c)) {
    throw new IllegalStateException(def.getEntryFilterClass() + " does not implement EntryFilter");
}

Type guard

boolean isEntryFilterClass(String className, NarClassLoader ncl) {
    try { return EntryFilter.class.isAssignableFrom(ncl.loadClass(className)); }
    catch (ClassNotFoundException e) { return false; }
}

Try / catch

try {
    EntryFilter f = provider.load(metadata);
} catch (IOException e) {
    log.error("{} does not implement EntryFilter; fix the definition or the class", e.getMessage());
}

Prevention

When it happens

Trigger: entryFilterClass in the filter definition points to a valid class that does not implement org.apache.pulsar.broker.service.plugin.EntryFilter (wrong class name, wrong version of the class, or a helper class referenced by mistake).

Common situations: Definition written against an old interface/package that changed between Pulsar versions; copy-pasted class name from another plugin type (e.g. a BrokerEntryMetadataFilter); class compiled against a different EntryFilter interface so instanceof fails.

Related errors


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