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
- 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)).
- If reading from a secret store that returns byte[] or char[], convert with the correct character encoding and zero out the source afterwards.
- 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
- Always supply password/secret configs as String or org.apache.kafka.common.config.types.Password, never as char[] or a custom type.
- Wrap secrets in Password so they are masked in logs and ConfigDef rendering.
- Load credentials from a secret manager / env var directly into a String - do not intermediate through JSON-parsed numbers.
- Validate the type in a single config-loader so a misparsed secret fails at startup, not mid-handshake.
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
- Expected value to be either true or false
- Expected value to be a 32-bit integer, but it was a value.ge
- Expected value to be a 16-bit integer (short), but it was a
- Invalid url in bootstrap.servers: {url}
- Invalid url in bootstrap.servers: {url}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/dc2157bed6d37fef.json.
Report an issue: GitHub.