apache/kafka · error · ConfigException

Expected value to be a string, but it was a value.getClass()

Error message

Expected value to be a string, but it was a value.getClass().getName()

What it means

Thrown by ConfigDef.parseType in the PASSWORD branch when the supplied value is neither a Password instance nor a String. Type.PASSWORD accepts org.apache.kafka.common.config.types.Password (already-wrapped secret) or a plain String that it will wrap via new Password(trimmed); any other runtime type is rejected so secrets are not silently coerced from numeric/object values.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java:730

                case BOOLEAN:
                    if (value instanceof String) {
                        if (trimmed.equalsIgnoreCase("true"))
                            return true;
                        else if (trimmed.equalsIgnoreCase("false"))
                            return false;
                        else
                            throw new ConfigException(name, value, "Expected value to be either true or false");
                    } else if (value instanceof Boolean)
                        return value;
                    else
                        throw new ConfigException(name, value, "Expected value to be either true or false");
                case PASSWORD:
                    if (value instanceof Password)
                        return value;
                    else if (value instanceof String)
                        return new Password(trimmed);
                    else
                        throw new ConfigException(name, value, "Expected value to be a string, but it was a " + value.getClass().getName());
                case STRING:
                    if (value instanceof String)
                        return trimmed;
                    else
                        throw new ConfigException(name, value, "Expected value to be a string, but it was a " + value.getClass().getName());
                case INT:
                    if (value instanceof Integer) {
                        return value;
                    } else if (value instanceof String) {
                        return Integer.parseInt(trimmed);
                    } else {
                        throw new ConfigException(name, value, "Expected value to be a 32-bit integer, but it was a " + value.getClass().getName());
                    }
                case SHORT:
                    if (value instanceof Short) {
                        return value;
                    } else if (value instanceof String) {
                        return Short.parseShort(trimmed);

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Convert the secret to a String or to org.apache.kafka.common.config.types.Password before placing it in the config map (e.g. new String(chars) or new Password(secret)).
  2. If reading from a secret store that returns byte[] or char[], convert with the correct character encoding and zero out the source afterwards.
  3. Ensure custom ConfigProvider implementations return String values from ConfigData so substitution yields a String the PASSWORD branch can wrap.

Example fix

// before
char[] secret = vault.get("keystore_pw");
cfg.put("ssl.keystore.password", secret); // char[] -> ConfigException

// after
import org.apache.kafka.common.config.types.Password;
cfg.put("ssl.keystore.password", new Password(new String(vault.get("keystore_pw"))));
Defensive patterns

Strategy: type-guard

Validate before calling

// A PASSWORD config expects a Password or a String (e.g. "ssl.keystore.password").
Object v = props.get(name);
if (v != null && !(v instanceof String) && !(v instanceof Password)) {
    throw new IllegalArgumentException(
        "Config '" + name + "' (PASSWORD) must be a String or Password, got " + v.getClass().getName());
}
// Wrap sensitive values as Password to keep them out of toString()/logs:
if (v instanceof String) props.put(name, new Password((String) v));

Type guard

static boolean isPasswordConfigValue(Object v) {
    if (v == null) return true;
    return v instanceof Password || v instanceof String;
}

Prevention

When it happens

Trigger: Passing a char[], byte[], Integer, Long, or arbitrary object as the value for a PASSWORD config key such as ssl.keystore.password, sasl.jaas.config, or connection.password; building config programmatically with a typed config library that returns non-String scalars.

Common situations: Secret loaded from a Vault/KMS SDK that hands back a byte[] or char[]; Spring/Typesafe Config returning a typed value for a sensitive field; a custom ConfigProvider returning a non-String value from get(...).

Related errors


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