{"record":{"id":"3b526e029041e9e2","repo":"grpc/grpc-java","slug":"value-s-for-key-s-in-s-is-not-list","errorCode":null,"errorMessage":"value '%s' for key '%s' in '%s' is not List","messagePattern":"value '(.+?)' for key '(.+?)' in '(.+?)' is not List","errorType":"validation","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/JsonUtil.java","lineNumber":45,"sourceCode":"\n/**\n * Helper utility to work with JSON values in Java types. Includes the JSON dialect used by\n * Protocol Buffers.\n */\npublic class JsonUtil {\n  /**\n   * Gets a list from an object for the given key.  If the key is not present, this returns null.\n   * If the value is not a List, throws an exception.\n   */\n  @Nullable\n  public static List<?> getList(Map<String, ?> obj, String key) {\n    assert key != null;\n    if (!obj.containsKey(key)) {\n      return null;\n    }\n    Object value = obj.get(key);\n    if (!(value instanceof List)) {\n      throw new ClassCastException(\n          String.format(\"value '%s' for key '%s' in '%s' is not List\", value, key, obj));\n    }\n    return (List<?>) value;\n  }\n\n  /**\n   * Gets a list from an object for the given key, and verifies all entries are objects.  If the key\n   * is not present, this returns null.  If the value is not a List or an entry is not an object,\n   * throws an exception.\n   */\n  @Nullable\n  public static List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {\n    List<?> list = getList(obj, key);\n    if (list == null) {\n      return null;\n    }\n    return checkObjectList(list);\n  }","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/JsonUtil.java#L27-L63","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"methodConfig\": {\"name\": [{}]} }\n// after\n{\"methodConfig\": [ {\"name\": [{}]} ] }","handlingStrategy":"validation","validationCode":"Object v = cfg.get(\"methodConfig\");\nif (v != null && !(v instanceof List)) throw new IllegalArgumentException(\"methodConfig must be an array\");","typeGuard":"List<?> asList(Object v) { return v instanceof List ? (List<?>) v : null; }","tryCatchPattern":"try { JsonUtil.getList(obj, \"methodConfig\"); }\ncatch (ClassCastException e) { log.error(\"bad service config: {}\", e.getMessage()); throw new InvalidConfigException(e); }","preventionTips":["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"],"tags":["grpc","json","config","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}