{"record":{"id":"3334b5729f6b4470","repo":"apache/pulsar","slug":"entryfilternames-can-t-be-empty-to-remove-entry-f","errorCode":null,"errorMessage":"entryFilterNames can't be empty. To remove entry filters use the remove method.","messagePattern":"entryFilterNames can't be empty\\. To remove entry filters use the remove method\\.","errorType":"http","errorClass":"org.apache.pulsar.broker.admin.RestException","httpStatus":400,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/AdminResource.java","lineNumber":956,"sourceCode":"        checkArgument(retention.getRetentionTimeInMinutes() >= -1,\n                \"Invalid retention policy: time limit must be >= -1\");\n        checkArgument((retention.getRetentionTimeInMinutes() != 0 && retention.getRetentionSizeInMB() != 0)\n                        || (retention.getRetentionTimeInMinutes() == 0 && retention.getRetentionSizeInMB() == 0),\n                \"Invalid retention policy: Setting a single time or size limit to 0 is invalid when \"\n                        + \"one of the limits has a non-zero value. Use the value of -1 instead of 0 to ignore a \"\n                        + \"specific limit. To disable retention both limits must be set to 0.\");\n    }\n\n    protected void validateEntryFilters(EntryFilters entryFilters) {\n        if (entryFilters == null) {\n            // remove entry filters\n            return;\n        }\n        if (StringUtils.isBlank(entryFilters.getEntryFilterNames())\n                || Arrays.stream(entryFilters.getEntryFilterNames().split(\",\"))\n                        .filter(n -> StringUtils.isNotBlank(n))\n                        .findAny().isEmpty()) {\n            throw new RestException(new RestException(Status.BAD_REQUEST,\n                    \"entryFilterNames can't be empty. To remove entry filters use the remove method.\"));\n        }\n        try {\n            pulsar().getBrokerService().getEntryFilterProvider()\n                    .validateEntryFilters(entryFilters.getEntryFilterNames());\n        } catch (InvalidEntryFilterException ex) {\n            throw new RestException(new RestException(Status.BAD_REQUEST, ex));\n        }\n    }\n\n    /**\n     * Check current exception whether is redirect exception.\n     *\n     * @param ex The throwable.\n     * @return Whether is redirect exception\n     */\n    protected static boolean isRedirectException(Throwable ex) {\n        Throwable realCause = FutureUtil.unwrapCompletionException(ex);","sourceCodeStart":938,"sourceCodeEnd":974,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/AdminResource.java#L938-L974","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 ','.","solutions":["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.","If you intend to SET filters, populate entryFilterNames with at least one valid, non-blank filter class name, comma-separated for multiple.","Trim/normalize your input before sending: filter out blank tokens and if none remain, switch to the remove call instead.","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."],"exampleFix":"// before (400: blank filter list meant as 'clear')\nadmin.namespaces().setEntryFilters(ns, new EntryFiltersImpl().setEntryFilterNames(\"\"));\n// after: remove instead\nadmin.namespaces().removeEntryFilters(ns);\n// or set real values\nadmin.namespaces().setEntryFilters(ns, new EntryFiltersImpl().setEntryFilterNames(\"com.acme.FilterA,com.acme.FilterB\"));","handlingStrategy":"validation","validationCode":"// Java\nString names = entryFilters.getEntryFilterNames();\nboolean valid = names != null && Arrays.stream(names.split(\",\")).anyMatch(n -> !n.isBlank());\nif (!valid) { admin.namespaces().removeEntryFilters(ns); return; }","typeGuard":null,"tryCatchPattern":"try {\n    admin.namespaces().setEntryFilters(ns, entryFilters);\n} catch (PulsarAdminException.BadRequestException e) {\n    if (e.getMessage().contains(\"entryFilterNames can't be empty\")) {\n        admin.namespaces().removeEntryFilters(ns); // removal is the remove API, not empty list\n    }\n}","preventionTips":["Never send EntryFilters with blank/whitespace-only entryFilterNames.","Treat 'clear filters' as a distinct remove API call, not an empty set.","Join filter lists defensively: filter blank tokens before joining with ','.","Validate filter class names against the broker's configured filter provider before sending."],"tags":["pulsar","broker","rest-bad-request","entry-filters","validation"],"backgroundTag":"empty-required-parameter","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}