{"record":{"id":"65e0db11c231da09","repo":"grpc/grpc-java","slug":"value-s-for-key-s-is-not-a-double","errorCode":null,"errorMessage":"value '%s' for key '%s' is not a double","messagePattern":"value '(.+?)' for key '(.+?)' is not a double","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/JsonUtil.java","lineNumber":116,"sourceCode":"  /**\n   * Gets a number from an object for the given key.  If the key is not present, this returns null.\n   * If the value does not represent a double, throws an exception.\n   */\n  @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);","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/JsonUtil.java#L98-L134","documentation":"JsonUtil.getNumberAsDouble accepts JSON numbers and, as a convenience, numeric strings. When the value is a String that Double.parseDouble cannot parse, it throws IllegalArgumentException('value ... is not a double'). (Non-number, non-string types hit a sibling 'is not a number' error.)","triggerScenarios":"A config key expected to be numeric (timeout in seconds/nanos, percentages in xDS configs) is a String that is not parseable — e.g. \"30s\", \"1.5x\", empty string, or a localized number with comma decimal separator.","commonSituations":"Authors writing durations with units (\"30s\") in JSON fields that require bare numbers; spreadsheet-exported configs with locale-formatted decimals; template placeholders left unsubstituted (\"${timeout}\").","solutions":["Replace the string with a raw JSON number: \"timeout\": \"30\" -> \"timeout\": 30","Strip units/symbols — gRPC durations with units belong in separate seconds/nanos fields, not in numeric values","Normalize locale decimal separators (',' -> '.') if the config is machine-generated","Validate numeric fields at config-load time before passing them to gRPC"],"exampleFix":"// before\n{\"timeoutSeconds\": \"30s\"}\n// after\n{\"timeoutSeconds\": 30}","handlingStrategy":"validation","validationCode":"Object v = cfg.get(\"timeoutSeconds\");\nif (v instanceof String && !((String) v).matches(\"-?\\\\d+(\\\\.\\\\d+)?\")) throw new IllegalArgumentException(\"timeoutSeconds must be a plain number, no units\");","typeGuard":null,"tryCatchPattern":"try { double d = JsonUtil.getNumberAsDouble(cfg, \"timeoutSeconds\"); }\ncatch (IllegalArgumentException e) { if (e.getMessage().contains(\"is not a double\")) { log.error(\"bad numeric field: {}\", e.getMessage()); } throw e; }","preventionTips":["Never write units (\"30s\") into numeric JSON fields — use bare numbers","Use the gRPC Duration shape ({seconds, nanos}) where durations are required","Reject template placeholders like \"${timeout}\" before deploy"],"tags":["grpc","json","config","numeric-parse"],"backgroundTag":"invalid-config-value","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}