apache/pulsar · error · org.apache.pulsar.broker.admin.RestException

entryFilterNames can't be empty. To remove entry filters use

Error message

entryFilterNames can't be empty. To remove entry filters use the remove method.

What it means

When updating a topic/namespace policy with entry filters, an entryFilterNames value that is blank or contains only separators/whitespace is rejected with HTTP 400. Entry filters are only ever set or replaced via this API; removal is a separate operation (setEntryFilters with null / the remove endpoint), so an empty list is treated as a caller mistake rather than a 'clear' request.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/AdminResource.java:956

        checkArgument(retention.getRetentionTimeInMinutes() >= -1,
                "Invalid retention policy: time limit must be >= -1");
        checkArgument((retention.getRetentionTimeInMinutes() != 0 && retention.getRetentionSizeInMB() != 0)
                        || (retention.getRetentionTimeInMinutes() == 0 && retention.getRetentionSizeInMB() == 0),
                "Invalid retention policy: Setting a single time or size limit to 0 is invalid when "
                        + "one of the limits has a non-zero value. Use the value of -1 instead of 0 to ignore a "
                        + "specific limit. To disable retention both limits must be set to 0.");
    }

    protected void validateEntryFilters(EntryFilters entryFilters) {
        if (entryFilters == null) {
            // remove entry filters
            return;
        }
        if (StringUtils.isBlank(entryFilters.getEntryFilterNames())
                || Arrays.stream(entryFilters.getEntryFilterNames().split(","))
                        .filter(n -> StringUtils.isNotBlank(n))
                        .findAny().isEmpty()) {
            throw new RestException(new RestException(Status.BAD_REQUEST,
                    "entryFilterNames can't be empty. To remove entry filters use the remove method."));
        }
        try {
            pulsar().getBrokerService().getEntryFilterProvider()
                    .validateEntryFilters(entryFilters.getEntryFilterNames());
        } catch (InvalidEntryFilterException ex) {
            throw new RestException(new RestException(Status.BAD_REQUEST, ex));
        }
    }

    /**
     * Check current exception whether is redirect exception.
     *
     * @param ex The throwable.
     * @return Whether is redirect exception
     */
    protected static boolean isRedirectException(Throwable ex) {
        Throwable realCause = FutureUtil.unwrapCompletionException(ex);

View on GitHub (pinned to 820761864e)

Solutions

  1. If you intend to REMOVE filters, use the remove path: call the removeEntryFilters/DELETE API or send the update without setting entryFilterNames (null), not an empty string.
  2. If you intend to SET filters, populate entryFilterNames with at least one valid, non-blank filter class name, comma-separated for multiple.
  3. Trim/normalize your input before sending: filter out blank tokens and if none remain, switch to the remove call instead.
  4. Verify entry filters are enabled on the broker (entryFilterAvailablity / broker config) — but note the 400 here is purely about the empty name list, independent of filter validity.

Example fix

// before (400: blank filter list meant as 'clear')
admin.namespaces().setEntryFilters(ns, new EntryFiltersImpl().setEntryFilterNames(""));
// after: remove instead
admin.namespaces().removeEntryFilters(ns);
// or set real values
admin.namespaces().setEntryFilters(ns, new EntryFiltersImpl().setEntryFilterNames("com.acme.FilterA,com.acme.FilterB"));
Defensive patterns

Strategy: validation

Validate before calling

// Java
String names = entryFilters.getEntryFilterNames();
boolean valid = names != null && Arrays.stream(names.split(",")).anyMatch(n -> !n.isBlank());
if (!valid) { admin.namespaces().removeEntryFilters(ns); return; }

Try / catch

try {
    admin.namespaces().setEntryFilters(ns, entryFilters);
} catch (PulsarAdminException.BadRequestException e) {
    if (e.getMessage().contains("entryFilterNames can't be empty")) {
        admin.namespaces().removeEntryFilters(ns); // removal is the remove API, not empty list
    }
}

Prevention

When it happens

Trigger: Calling the admin policy-update endpoint (e.g. POST/PUT namespace or topic policies) with an EntryFilters body where entryFilterNames is null/empty/whitespace or a comma string like ",, " — i.e. all split tokens blank.

Common situations: 1) Client code sends an empty EntryFilters object intending to clear filters. 2) A config template has entryFilterNames bound to an empty env var. 3) A UI joins filter names with ',' and the list was empty, producing ','.

Related errors


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