apache/kafka · error · ClassCastException

Non-string value found in original settings for key entry.ge

Error message

Non-string value found in original settings for key entry.getKey(): (entry.getValue() == null ? null : entry.getValue().getClass().getName())

What it means

ClassCastException thrown by AbstractConfig.originalsStrings() when iterating the raw `originals` map and encountering a value that is not a String. originalsStrings() is documented to require all original settings to be strings; it constructs a Map<String,String> and casts each value. The message reports the offending key and (if non-null) the value's Java class name so the caller can see exactly which entry is mis-typed. This is a type-contract violation on the inputs supplied to the config constructor, not a parse error.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/config/AbstractConfig.java:268

    public Map<String, Object> originals(Map<String, Object> configOverrides) {
        Map<String, Object> copy = new RecordingMap<>();
        copy.putAll(originals);
        copy.putAll(configOverrides);
        return copy;
    }

    /**
     * Get all the original settings, ensuring that all values are of type String.
     *
     * @return the original settings
     * @throws ClassCastException if any of the values are not strings
     */
    public Map<String, String> originalsStrings() {
        Map<String, String> copy = new RecordingMap<>();
        for (Map.Entry<String, ?> entry : originals.entrySet()) {
            if (!(entry.getValue() instanceof String))
                throw new ClassCastException("Non-string value found in original settings for key " + entry.getKey() +
                        ": " + (entry.getValue() == null ? null : entry.getValue().getClass().getName()));
            copy.put(entry.getKey(), (String) entry.getValue());
        }
        return copy;
    }

    /**
     * Gets all original settings with the given prefix, stripping the prefix before adding it to the output.
     *
     * @param prefix the prefix to use as a filter
     * @return a Map containing the settings with the prefix
     */
    public Map<String, Object> originalsWithPrefix(String prefix) {
        return originalsWithPrefix(prefix, true);
    }

    /**
     * Gets all original settings with the given prefix.

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Supply originals as String values only (e.g. pass a Properties object or Map<String,String> with list values as comma-separated strings), so originalsStrings() can return them verbatim.
  2. If you need typed values, use the parsed accessors (getList, getInt, ...) instead of originalsStrings().
  3. Audit which key triggered the cast (named in the message) and convert that entry to a string at the source.
  4. Avoid mixing a pre-parsed Map<String,Object> with code that expects originalsStrings(); pick one representation.

Example fix

// before: originals contain a non-String value
Map<String, Object> originals = new HashMap<>();
originals.put("bootstrap.servers", Arrays.asList("host1:9092", "host2:9092"));
AbstractConfig config = new AbstractConfig(def, originals);
Map<String, String> strings = config.originalsStrings(); // ClassCastException: List

// after: pass originals as strings
Map<String, Object> originals = new HashMap<>();
originals.put("bootstrap.servers", "host1:9092,host2:9092");
AbstractConfig config = new AbstractConfig(def, originals);
Map<String, String> strings = config.originalsStrings(); // ok
Defensive patterns

Strategy: type-guard

Validate before calling

// originalsStrings() requires every value to be a String; pre-filter or coerce.
java.util.Map<String, String> safe = new java.util.HashMap<>();
for (java.util.Map.Entry<String, ?> e : config.originals().entrySet()) {
    Object v = e.getValue();
    if (v instanceof String s) {
        safe.put(e.getKey(), s);
    } else if (v != null) {
        safe.put(e.getKey(), String.valueOf(v)); // explicit coercion, no surprise CCE
    }
}

Type guard

boolean allOriginalsAreStrings(org.apache.kafka.common.config.AbstractConfig cfg) {
    return cfg.originals().values().stream().allMatch(v -> v == null || v instanceof String);
}

Try / catch

try {
    Map<String, String> raw = config.originalsStrings();
} catch (ClassCastException cce) {
    // message: "Non-string value found in original settings for key ..."
    log.warn("Mixing typed and string originals is unsafe; coercing manually", cce);
    Map<String, String> raw = config.originals().entrySet().stream()
        .collect(java.util.stream.Collectors.toMap(
            Map.Entry::getKey,
            e -> e.getValue() == null ? null : String.valueOf(e.getValue())));
}

Prevention

When it happens

Trigger: Calling config.originalsStrings() after building an AbstractConfig from a Map<?,?> originals that contains a non-String value, e.g. a List (for a list-typed property supplied programmatically rather than as a comma-separated string), a Number/Boolean, or a Password object. Connect and some tools call originalsStrings() to externalize or log settings as strings.

Common situations: See trigger scenarios.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/02b0f33c2dee72d7.json. Report an issue: GitHub.