grpc/grpc-java · error · IllegalArgumentException
value '%s' for key '%s' in '%s' is not a number
Error message
value '%s' for key '%s' in '%s' is not a number
What it means
JsonUtil.getNumberAsDouble requires the JSON value to be a number (or a numeric string). When the value is neither — an object, array, or boolean — it throws IllegalArgumentException('value ... is not a number'), including the value, key, and parent object in the message.
Source
Thrown at core/src/main/java/io/grpc/internal/JsonUtil.java:120
@Nullable
public static Double getNumberAsDouble(Map<String, ?> obj, String key) {
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (value instanceof Double) {
return (Double) value;
}
if (value instanceof String) {
try {
return Double.parseDouble((String) value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not a double", value, key));
}
}
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' in '%s' is not a number", value, key, obj));
}
/**
* Gets a number from an object for the given key, casted to an integer. If the key is not
* present, this returns null. If the value does not represent an integer, throws an exception.
*/
@Nullable
public static Integer getNumberAsInteger(Map<String, ?> obj, String key) {
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (value instanceof Double) {
Double d = (Double) value;
int i = d.intValue();
if (i != d) {View on GitHub (pinned to 64daddc1f3)
Solutions
- Fix the JSON so the key maps to a plain number (or numeric string)
- Cross-check the field against the gRPC service config / xDS schema documentation
- Check the parent object printed in the message to find which fragment introduced the wrong type
- Pin and update the config-generating tool so it emits the documented types
Example fix
// before
{"timeoutSeconds": {"value": 30}}
// after
{"timeoutSeconds": 30} Defensive patterns
Strategy: validation
Validate before calling
Object v = cfg.get("timeoutSeconds");
if (v != null && !(v instanceof Number) && !(v instanceof String)) throw new IllegalArgumentException("timeoutSeconds must be a number"); Type guard
boolean isNumberLike(Object v) { return v instanceof Number || v instanceof String; } Try / catch
try { double d = JsonUtil.getNumberAsDouble(cfg, "timeoutSeconds"); }
catch (IllegalArgumentException e) { if (e.getMessage().contains("is not a number")) { log.error("wrong JSON type: {}", e.getMessage()); } throw e; } Prevention
- Schema-validate JSON config at load time
- Ensure config merging cannot overwrite scalars with objects
- Match the documented types in the gRPC service-config/xDS specs
When it happens
Trigger: A config key expected to be numeric holds a structured JSON value — e.g. writing an object/array where a number is required in service config or xDS bootstrap fields like timeout or percentage.
Common situations: Schema misunderstanding: author nests extra fields under the numeric key; generator bug emitting a wrong JSON type; merging config fragments so an object overwrites 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 List
- value '%s' for key '%s' in '%s' is not object
- 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/630315dc709329d6.
Report an issue: GitHub.