apache/pulsar · warning · RestException
property filter must be in the form key=value, got: ${entry}
Error message
property filter must be in the form key=value, got: ${entry} What it means
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.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java:148
}
/**
* Parse {@code key=value} entries from a list of query parameter values into a map.
* Accepts {@code null} / empty input. Rejects malformed entries (no {@code =}, empty
* key, or empty value) with a 412.
*/
private static Map<String, String> parseKeyValuePairs(List<String> entries) {
if (entries == null || entries.isEmpty()) {
return Map.of();
}
Map<String, String> result = new java.util.LinkedHashMap<>(entries.size());
for (String entry : entries) {
if (entry == null || entry.isEmpty()) {
continue;
}
int eq = entry.indexOf('=');
if (eq <= 0 || eq == entry.length() - 1) {
throw new RestException(Response.Status.fromStatusCode(412),
"property filter must be in the form key=value, got: " + entry);
}
result.put(entry.substring(0, eq), entry.substring(eq + 1));
}
return result;
}
// --- Create ---
@PUT
@Path("/{tenant}/{namespace}/{topic}")
@Operation(summary = "Create a new scalable topic.")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Scalable topic created successfully"),
@ApiResponse(responseCode = "401",
description = "Don't have permission to administrate resources on this tenant"),
@ApiResponse(responseCode = "403", description = "Don't have admin permission on the namespace"),
@ApiResponse(responseCode = "409", description = "Scalable topic already exists"),View on GitHub (pinned to 820761864e)
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
Example fix
// before ?properties=env // after ?properties=env=prod
Defensive patterns
Strategy: validation
Validate before calling
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); } Type guard
boolean isValidFilter(String e) { int i = e == null ? -1 : e.indexOf('='); return i > 0 && i < e.length() - 1; } Try / catch
try { admin.topics().list(namespace, filters); } catch (PulsarAdminException e) { if (e.getStatusCode() == 412) { /* fix key=value filters */ } } Prevention
- 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
When it happens
Trigger: Endpoints using propertyFilters (e.g. listing topics with property filters) with query params like ?properties=key or ?properties==value or ?properties=key=.
Common situations: Hand-built URLs missing the value after '='; shell quoting stripping parts of the filter; passing multiple values where only key=value pairs are allowed.
Related errors
- cluster data is required
- Peer cluster ${peerCluster} does not exist
- Cluster ${cluster} does not exist.
- ClusterIds should not be null or empty
- Invalid cluster id: ${clusterId}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/5ed926d6a0db9563.
Report an issue: GitHub.