{"id":"dc2157bed6d37fef","repo":"apache/kafka","slug":"expected-value-to-be-a-string-but-it-was-a-value","errorCode":null,"errorMessage":"Expected value to be a string, but it was a value.getClass().getName()","messagePattern":"Expected value to be a string, but it was a value\\.getClass\\(\\)\\.getName\\(\\)","errorType":"validation","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java","lineNumber":730,"sourceCode":"                case BOOLEAN:\n                    if (value instanceof String) {\n                        if (trimmed.equalsIgnoreCase(\"true\"))\n                            return true;\n                        else if (trimmed.equalsIgnoreCase(\"false\"))\n                            return false;\n                        else\n                            throw new ConfigException(name, value, \"Expected value to be either true or false\");\n                    } else if (value instanceof Boolean)\n                        return value;\n                    else\n                        throw new ConfigException(name, value, \"Expected value to be either true or false\");\n                case PASSWORD:\n                    if (value instanceof Password)\n                        return value;\n                    else if (value instanceof String)\n                        return new Password(trimmed);\n                    else\n                        throw new ConfigException(name, value, \"Expected value to be a string, but it was a \" + value.getClass().getName());\n                case STRING:\n                    if (value instanceof String)\n                        return trimmed;\n                    else\n                        throw new ConfigException(name, value, \"Expected value to be a string, but it was a \" + value.getClass().getName());\n                case INT:\n                    if (value instanceof Integer) {\n                        return value;\n                    } else if (value instanceof String) {\n                        return Integer.parseInt(trimmed);\n                    } else {\n                        throw new ConfigException(name, value, \"Expected value to be a 32-bit integer, but it was a \" + value.getClass().getName());\n                    }\n                case SHORT:\n                    if (value instanceof Short) {\n                        return value;\n                    } else if (value instanceof String) {\n                        return Short.parseShort(trimmed);","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java#L712-L748","documentation":"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.","triggerScenarios":"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.","commonSituations":"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(...).","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."],"exampleFix":"// before\nchar[] secret = vault.get(\"keystore_pw\");\ncfg.put(\"ssl.keystore.password\", secret); // char[] -> ConfigException\n\n// after\nimport org.apache.kafka.common.config.types.Password;\ncfg.put(\"ssl.keystore.password\", new Password(new String(vault.get(\"keystore_pw\"))));","handlingStrategy":"type-guard","validationCode":"// A PASSWORD config expects a Password or a String (e.g. \"ssl.keystore.password\").\nObject v = props.get(name);\nif (v != null && !(v instanceof String) && !(v instanceof Password)) {\n    throw new IllegalArgumentException(\n        \"Config '\" + name + \"' (PASSWORD) must be a String or Password, got \" + v.getClass().getName());\n}\n// Wrap sensitive values as Password to keep them out of toString()/logs:\nif (v instanceof String) props.put(name, new Password((String) v));","typeGuard":"static boolean isPasswordConfigValue(Object v) {\n    if (v == null) return true;\n    return v instanceof Password || v instanceof String;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["config","password","type-coercion","secrets"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}