apache/pulsar · error · IllegalArgumentException

Invalid MetadataStoreConfig query parameter '${param}'. Expe

Error message

Invalid MetadataStoreConfig query parameter '${param}'. Expected key=value

What it means

MetadataStoreUrl.parse() splits the metadata store URL into provider params and MetadataStoreConfig params. A query param whose key is a known config key but lacks a '=' separator (i.e., a bare flag like ?sessionTimeoutMillis) cannot be applied and throws IllegalArgumentException 'Expected key=value'.

Source

Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/MetadataStoreUrl.java:55

        String query = metadataStoreUrl.substring(queryStart + 1);
        if (query.isEmpty()) {
            return new MetadataStoreUrl(url, Map.of());
        }

        Map<String, String> configParams = new LinkedHashMap<>();
        List<String> providerParams = new ArrayList<>();
        for (String param : query.split("&", -1)) {
            if (param.isEmpty()) {
                continue;
            }
            int separator = param.indexOf('=');
            String key = decodeQueryParam(separator > 0 ? param.substring(0, separator) : param);
            if (!MetadataStoreConfigQueryParams.contains(key)) {
                providerParams.add(param);
                continue;
            }
            if (separator <= 0) {
                throw new IllegalArgumentException("Invalid MetadataStoreConfig query parameter '" + param
                        + "'. Expected key=value");
            }

            String value = decodeQueryParam(param.substring(separator + 1));
            configParams.put(key, value);
        }

        if (!providerParams.isEmpty()) {
            url += "?" + String.join("&", providerParams);
        }
        return new MetadataStoreUrl(url, Map.copyOf(configParams));
    }

    private static String removeMetadataStoreScheme(String metadataServiceUri) {
        String prefix = AbstractMetadataDriver.METADATA_STORE_SCHEME + ":";
        if (metadataServiceUri.startsWith(prefix)) {
            return metadataServiceUri.substring(prefix.length());
        }

View on GitHub (pinned to 820761864e)

Solutions

  1. Append '=value' to the parameter (e.g. sessionTimeoutMillis=30000) or remove the bare key entirely.
  2. Check the full URL wasn't truncated by config tooling or shell escaping.
  3. Verify the param belongs in the config section vs provider params — unknown keys are routed to providerParams and won't trigger this.

Example fix

// before
zk://zk1:2181/ledgers?sessionTimeoutMillis
// after
zk://zk1:2181/ledgers?sessionTimeoutMillis=30000
Defensive patterns

Strategy: validation

Validate before calling

for (String param : query.split("&")) {
  int sep = param.indexOf('=');
  if (sep <= 0 && MetadataStoreConfigQueryParams.contains(decode(param)))
    throw new IllegalArgumentException("param needs key=value: " + param);
}

Prevention

When it happens

Trigger: A known config key appearing in the query string without '=value', e.g. metadata-store-url: zk://host:2181/ledgers?sessionTimeoutMillis — from truncation, typos, or hand-editing URLs.

Common situations: Truncated URLs in configs; removing the value but leaving the key and '?key'; mistakes when converting provider-specific params into config params.

Related errors


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