apache/pulsar · error · IllegalArgumentException

Failed to parse tlsFactoryConfig as a JSON object

Error message

Failed to parse tlsFactoryConfig as a JSON object

What it means

IllegalArgumentException thrown by TlsFactorySupport.parseFactoryConfig when the tlsFactoryConfig value cannot be parsed as a JSON object of Map<String,String>. The method first tries a full JSON parse via ObjectMapperFactory; any exception (malformed JSON, wrong JSON shape, non-string values) is wrapped with this message. tlsFactoryConfig is expected to be either a JSON object like {"key":"value"} or a comma-separated key=value list.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/tls/TlsFactorySupport.java:196

     * map; a value starting with <code>{</code> is parsed as a JSON object; otherwise it is parsed as a
     * comma-separated {@code key=value} list.
     *
     * @param tlsFactoryConfig the configured factory params (may be null/blank)
     * @return an immutable params map (possibly empty)
     */
    public static Map<String, String> parseFactoryConfig(String tlsFactoryConfig) {
        if (StringUtils.isBlank(tlsFactoryConfig)) {
            return Map.of();
        }
        String trimmed = tlsFactoryConfig.trim();
        if (trimmed.startsWith("{")) {
            try {
                Map<String, String> parsed = ObjectMapperFactory.getMapper().reader()
                        .forType(new TypeReference<Map<String, String>>() {})
                        .readValue(trimmed);
                return parsed == null ? Map.of() : Map.copyOf(parsed);
            } catch (Exception e) {
                throw new IllegalArgumentException("Failed to parse tlsFactoryConfig as a JSON object", e);
            }
        }
        Map<String, String> map = new LinkedHashMap<>();
        for (String pair : trimmed.split(",")) {
            String entry = pair.trim();
            if (entry.isEmpty()) {
                continue;
            }
            int eq = entry.indexOf('=');
            if (eq < 0) {
                map.put(entry, "");
            } else {
                map.put(entry.substring(0, eq).trim(), entry.substring(eq + 1).trim());
            }
        }
        return Map.copyOf(map);
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Rewrite tlsFactoryConfig as valid JSON with double quotes: {"provider":"jdk"}
  2. Ensure every JSON value is a string (quote numbers and booleans)
  3. Validate the JSON with a linter (jq) before deploying
  4. Alternatively use the simple comma-separated key=value form (k1=v1,k2=v2) which the parser falls back to

Example fix

// before (broker.conf)
tlsFactoryConfig={'key':'value',}
// after
tlsFactoryConfig={"key":"value"}
Defensive patterns

Strategy: validation

Validate before calling

String cfg = conf.getTlsFactoryConfig();
if (cfg != null && cfg.trim().startsWith("{")) {
    try {
        new ObjectMapper().readValue(cfg, new TypeReference<Map<String, String>>() {});
    } catch (Exception e) {
        throw new IllegalArgumentException("tlsFactoryConfig is not a valid JSON string map", e);
    }
}

Prevention

When it happens

Trigger: Setting broker/service tlsFactoryConfig to malformed JSON (e.g. {'key':'value'} with single quotes, trailing commas, unquoted keys) so readValue() throws; also thrown upstream if a non-string JSON value (number/bool/nested object) makes the TypeReference<Map<String,String>> binding fail.

Common situations: Config copied from docs with single quotes instead of double quotes; shell or YAML config stripping double quotes; users supplying key=value pairs with stray characters that also fail the fallback comma parser; upgrading and migrating a config that previously used a different format.

Understand the failure class

Related errors


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