{"record":{"id":"630315dc709329d6","repo":"grpc/grpc-java","slug":"value-s-for-key-s-in-s-is-not-a-number","errorCode":null,"errorMessage":"value '%s' for key '%s' in '%s' is not a number","messagePattern":"value '(.+?)' for key '(.+?)' in '(.+?)' is not a number","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/JsonUtil.java","lineNumber":120,"sourceCode":"  @Nullable\n  public static Double getNumberAsDouble(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 Double) {\n      return (Double) value;\n    }\n    if (value instanceof String) {\n      try {\n        return Double.parseDouble((String) value);\n      } catch (NumberFormatException e) {\n        throw new IllegalArgumentException(\n            String.format(\"value '%s' for key '%s' is not a double\", value, key));\n      }\n    }\n    throw new IllegalArgumentException(\n        String.format(\"value '%s' for key '%s' in '%s' is not a number\", value, key, obj));\n  }\n\n  /**\n   * Gets a number from an object for the given key, casted to an integer.  If the key is not\n   * present, this returns null.  If the value does not represent an integer, throws an exception.\n   */\n  @Nullable\n  public static Integer getNumberAsInteger(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 Double) {\n      Double d = (Double) value;\n      int i = d.intValue();\n      if (i != d) {","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/JsonUtil.java#L102-L138","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"timeoutSeconds\": {\"value\": 30}}\n// after\n{\"timeoutSeconds\": 30}","handlingStrategy":"validation","validationCode":"Object v = cfg.get(\"timeoutSeconds\");\nif (v != null && !(v instanceof Number) && !(v instanceof String)) throw new IllegalArgumentException(\"timeoutSeconds must be a number\");","typeGuard":"boolean isNumberLike(Object v) { return v instanceof Number || v instanceof String; }","tryCatchPattern":"try { double d = JsonUtil.getNumberAsDouble(cfg, \"timeoutSeconds\"); }\ncatch (IllegalArgumentException e) { if (e.getMessage().contains(\"is not a number\")) { log.error(\"wrong JSON type: {}\", e.getMessage()); } throw e; }","preventionTips":["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"],"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"}