grpc/grpc-java · error · ClassCastException
value ' ' for key ' ' in ' ' is not String
Error message
value '%s' for key '%s' in '%s' is not String
What it means
getString requires that a key present in the JSON object maps to a String; otherwise it throws ClassCastException naming the value, key, and whole object. gRPC uses it when parsing string config fields (e.g. LB policy names, target strings), and strict typing avoids silent coercion bugs.
Solutions
- Quote the value in the JSON so it is a string: 5 -> "5".
- Check the third '%s' in the message to see the whole offending object and locate the mis-typed field.
- Add schema validation for string fields before passing config to gRPC.
Example fix
// before
{"loadBalancingPolicy": 5}
// after
{"loadBalancingPolicy": "round_robin"} Defensive patterns
Strategy: type-guard
Validate before calling
Object v = config.get("loadBalancingPolicy");
if (v != null && !(v instanceof String)) {
throw new IllegalArgumentException("loadBalancingPolicy must be a string, got: " + v.getClass());
} Type guard
boolean isString(Object v) { return v instanceof String; } Try / catch
try {
String policy = JsonUtil.getString(config, "loadBalancingPolicy");
} catch (ClassCastException e) {
log.error("String config field has wrong type: " + e.getMessage());
} Prevention
- Quote all string config values, including numeric-looking IDs.
- Disable auto-typing in config generators for string fields.
- Validate string fields with JSON Schema.
When it happens
Trigger: JsonUtil.getString(map, key) where the value is a number, boolean, list, or object — e.g. {"loadBalancingPolicy": 5} or {"method": {"a":1}}.
Common situations: Service config with an unquoted number or boolean where a string is expected; JSON tooling that auto-types values (dates, IDs becoming numbers); nested object pasted into a string field.
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 for idx in is not object
- value ' ' for idx in ' ' is not string
- value ' ' for key ' ' in ' ' is not Boolean
- Authorization policy should be a JSON object. Found: null
- Number expected to be integer:
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/b9a5b076435849d8.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/io/grpc/internal/JsonUtil.java:198
}
}
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not a long integer", value, key));
}
/**
* Gets a string from an object for the given key. If the key is not present, this returns null.
* If the value is not a String, throws an exception.
*/
@Nullable
public static String getString(Map<String, ?> obj, String key) {
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (!(value instanceof String)) {
throw new ClassCastException(
String.format("value '%s' for key '%s' in '%s' is not String", value, key, obj));
}
return (String) value;
}
/**
* Gets a string from an object for the given key, parsed as a duration (defined by protobuf). If
* the key is not present, this returns null. If the value is not a String or not properly
* formatted, throws an exception.
*/
public static Long getStringAsDuration(Map<String, ?> obj, String key) {
String value = getString(obj, key);
if (value == null) {
return null;
}
try {
return parseDuration(value);
} catch (ParseException e) {View on GitHub (pinned to 64daddc1f3)