apache/pulsar · error · java.lang.RuntimeException

Entry filter `${name}` cannot be loaded, see the broker logs

Error message

Entry filter `${name}` cannot be loaded, see the broker logs for further details

What it means

After resolving the filter definition, load() obtains a NarClassLoader for the archive path. If getNarClassLoader returns null (the archive could not be opened/loaded; details are logged), the provider throws a RuntimeException pointing the user to broker logs.

Source

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

        }

        return ObjectMapperFactory.getYamlMapper().reader().readValue(
                configStr, EntryFilterDefinition.class
        );
    }

    @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)

View on GitHub (pinned to 820761864e)

Solutions

  1. Check broker logs at ERROR level for the underlying NAR load failure
  2. Confirm the archive file exists and is readable at metadata.getArchivePath() on this broker
  3. Redeploy the NAR to the entryFiltersDirectory and restart the broker

Example fix

// before
NAR missing: /pulsar/entryfilters/ (empty directory)
// after
cp audit-filter.nar /pulsar/entryfilters/ && chown pulsar:pulsar /pulsar/entryfilters/audit-filter.nar && restart broker
Defensive patterns

Strategy: try-catch

Validate before calling

Path archive = Path.of(metadata.getArchivePath());
if (!Files.isRegularFile(archive) || !Files.isReadable(archive)) {
    throw new IllegalStateException("Filter NAR missing/unreadable: " + archive);
}

Try / catch

try {
    EntryFilter f = provider.load(metadata);
} catch (RuntimeException e) {
    log.error("NAR load failed for {}; inspect broker logs for the root cause", metadata.getArchivePath(), e);
}

Prevention

When it happens

Trigger: load() called with metadata whose archivePath is null, nonexistent, unreadable, or whose NAR failed classloader construction.

Common situations: NAR file deleted or moved after policy set; wrong permissions on the entryFilters directory; broker running in container without the NAR volume mounted; corrupted NAR upload.

Related errors


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