{"record":{"id":"5ed926d6a0db9563","repo":"apache/pulsar","slug":"property-filter-must-be-in-the-form-key-value-got","errorCode":null,"errorMessage":"property filter must be in the form key=value, got: ${entry}","messagePattern":"property filter must be in the form key=value, got: (.+?)","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java","lineNumber":148,"sourceCode":"    }\n\n    /**\n     * Parse {@code key=value} entries from a list of query parameter values into a map.\n     * Accepts {@code null} / empty input. Rejects malformed entries (no {@code =}, empty\n     * key, or empty value) with a 412.\n     */\n    private static Map<String, String> parseKeyValuePairs(List<String> entries) {\n        if (entries == null || entries.isEmpty()) {\n            return Map.of();\n        }\n        Map<String, String> result = new java.util.LinkedHashMap<>(entries.size());\n        for (String entry : entries) {\n            if (entry == null || entry.isEmpty()) {\n                continue;\n            }\n            int eq = entry.indexOf('=');\n            if (eq <= 0 || eq == entry.length() - 1) {\n                throw new RestException(Response.Status.fromStatusCode(412),\n                        \"property filter must be in the form key=value, got: \" + entry);\n            }\n            result.put(entry.substring(0, eq), entry.substring(eq + 1));\n        }\n        return result;\n    }\n\n    // --- Create ---\n\n    @PUT\n    @Path(\"/{tenant}/{namespace}/{topic}\")\n    @Operation(summary = \"Create a new scalable topic.\")\n    @ApiResponses(value = {\n            @ApiResponse(responseCode = \"204\", description = \"Scalable topic created successfully\"),\n            @ApiResponse(responseCode = \"401\",\n                    description = \"Don't have permission to administrate resources on this tenant\"),\n            @ApiResponse(responseCode = \"403\", description = \"Don't have admin permission on the namespace\"),\n            @ApiResponse(responseCode = \"409\", description = \"Scalable topic already exists\"),","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java#L130-L166","documentation":"ScalableTopics.parseKeyValuePairs parses property-filter query entries as key=value. An entry without '=' at all, an empty key ('=v'), or an empty value ('k=') is rejected with HTTP 412. The message interpolates the offending entry.","triggerScenarios":"Endpoints using propertyFilters (e.g. listing topics with property filters) with query params like ?properties=key or ?properties==value or ?properties=key=.","commonSituations":"Hand-built URLs missing the value after '='; shell quoting stripping parts of the filter; passing multiple values where only key=value pairs are allowed.","solutions":["Provide each filter as strict key=value with non-empty key and non-empty value","Check shell quoting so '=' survives (quote the whole URL/param)","Drop empty entries — they are skipped, but malformed non-empty entries throw"],"exampleFix":"// before\n?properties=env\n// after\n?properties=env=prod","handlingStrategy":"validation","validationCode":"for (String e : filters) { if (e != null && !e.isEmpty() && !(e.contains(\"=\") && e.indexOf('=') > 0 && e.indexOf('=') < e.length()-1)) throw new IllegalArgumentException(\"bad filter: \" + e); }","typeGuard":"boolean isValidFilter(String e) { int i = e == null ? -1 : e.indexOf('='); return i > 0 && i < e.length() - 1; }","tryCatchPattern":"try { admin.topics().list(namespace, filters); } catch (PulsarAdminException e) { if (e.getStatusCode() == 412) { /* fix key=value filters */ } }","preventionTips":["Build filters programmatically as Map entries joined as key=value","Quote URLs in shell to protect '=' characters","Validate filter strings before appending to query strings"],"tags":["validation","rest-api","query-params"],"backgroundTag":"malformed-key-value-filter","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"}