grpc/grpc-java · error · ClassCastException
value '%s' for key '%s' in '%s' is not List
Error message
value '%s' for key '%s' in '%s' is not List
What it means
JsonUtil.getList looks up a key in a parsed JSON object (Map<String,?>) and expects the value to be a JSON array (List). If the key exists but the value is any other JSON type, it throws ClassCastException with a message showing the value, key, and containing object.
Source
Thrown at core/src/main/java/io/grpc/internal/JsonUtil.java:45
/**
* Helper utility to work with JSON values in Java types. Includes the JSON dialect used by
* Protocol Buffers.
*/
public class JsonUtil {
/**
* Gets a list from an object for the given key. If the key is not present, this returns null.
* If the value is not a List, throws an exception.
*/
@Nullable
public static List<?> getList(Map<String, ?> obj, String key) {
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (!(value instanceof List)) {
throw new ClassCastException(
String.format("value '%s' for key '%s' in '%s' is not List", value, key, obj));
}
return (List<?>) value;
}
/**
* Gets a list from an object for the given key, and verifies all entries are objects. If the key
* is not present, this returns null. If the value is not a List or an entry is not an object,
* throws an exception.
*/
@Nullable
public static List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {
List<?> list = getList(obj, key);
if (list == null) {
return null;
}
return checkObjectList(list);
}View on GitHub (pinned to 64daddc1f3)
Solutions
- Fix the JSON so the key holds an array: change "key": "value" to "key": ["value"]
- Validate the config against the expected schema before feeding it to gRPC
- Check which file produced the object (it is printed in the message) and correct that source
- If a single item is allowed, check the producer's schema — newer versions may accept either shape
Example fix
// before
{"methodConfig": {"name": [{}]} }
// after
{"methodConfig": [ {"name": [{}]} ] } Defensive patterns
Strategy: validation
Validate before calling
Object v = cfg.get("methodConfig");
if (v != null && !(v instanceof List)) throw new IllegalArgumentException("methodConfig must be an array"); Type guard
List<?> asList(Object v) { return v instanceof List ? (List<?>) v : null; } Try / catch
try { JsonUtil.getList(obj, "methodConfig"); }
catch (ClassCastException e) { log.error("bad service config: {}", e.getMessage()); throw new InvalidConfigException(e); } Prevention
- Validate service-config JSON against the gRPC schema at load time
- Keep configs in version control and schema-lint them in CI
- Remember JSON arrays require brackets even for single elements
When it happens
Trigger: Calling getList/list on a config object (e.g. gRPC service config, xDS bootstrap JSON) where the target key holds a string, number, boolean, or object instead of an array.
Common situations: Hand-edited service config or xDS bootstrap files where a field like 'methodConfig' or a retry list was written as a single object/string; config generated by tooling with a schema change; typo reusing a key that stores a scalar.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- value '%s' for key '%s' in '%s' is not object
- value '%s' for key '%s' in '%s' is not a number
- Authorization policy should be a JSON object. Found: null
- value '%s' for key '%s' is not a double
- Number expected to be integer:
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/3b526e029041e9e2.
Report an issue: GitHub.