{"record":{"id":"7f30351c40e03980","repo":"google/gson","slug":"string-created-by-is-not-a-valid-json-number","errorCode":null,"errorMessage":"String created by {} is not a valid JSON number: {}","messagePattern":"String created by (.+?) is not a valid JSON number: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/stream/JsonWriter.java","lineNumber":651,"sourceCode":"  public JsonWriter value(Number value) throws IOException {\n    if (value == null) {\n      return nullValue();\n    }\n\n    writeDeferredName();\n    String string = value.toString();\n    Class<? extends Number> numberClass = value.getClass();\n\n    if (!alwaysCreatesValidJsonNumber(numberClass)) {\n      // Validate that string is valid before writing it directly to JSON output\n      if (string.equals(\"-Infinity\") || string.equals(\"Infinity\") || string.equals(\"NaN\")) {\n        if (strictness != Strictness.LENIENT) {\n          throw new IllegalArgumentException(\"Numeric values must be finite, but was \" + string);\n        }\n      } else if (numberClass != Float.class\n          && numberClass != Double.class\n          && !VALID_JSON_NUMBER_PATTERN.matcher(string).matches()) {\n        throw new IllegalArgumentException(\n            \"String created by \" + numberClass + \" is not a valid JSON number: \" + string);\n      }\n    }\n\n    beforeValue();\n    out.append(string);\n    return this;\n  }\n\n  /**\n   * Encodes {@code null}.\n   *\n   * @return this writer.\n   */\n  @CanIgnoreReturnValue\n  public JsonWriter nullValue() throws IOException {\n    if (deferredName != null) {\n      if (serializeNulls) {","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/stream/JsonWriter.java#L633-L669","documentation":"Thrown by JsonWriter.value(Number) (JsonWriter.java:648-653) when the Number subclass is not one of the always-valid types (Integer, Long, Byte, Short, BigDecimal, BigInteger, AtomicInteger, AtomicLong) and its toString() does not match the VALID_JSON_NUMBER_PATTERN regex (-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][-+]?[0-9]+)?). This catches custom Number implementations whose string form would produce invalid JSON (leading zeros, hex, locale commas, trailing letters, etc.).","triggerScenarios":"Passing a custom Number subclass (e.g. a LazyParsedNumber or domain-specific Number) whose toString() returns something like \"0x1A\", \"1,000\", \"1.0e\", \"+5\", or \"01\". Also triggered by a Number that returns \"\" or whitespace.","commonSituations":"Custom Number types for performance (lazy parsing, cached strings); third-party libraries exposing their own Number subclasses; locale-aware toString implementations; numbers carrying metadata in their string form.","solutions":["Convert the custom Number to a known-good type before writing: writer.value(number.doubleValue()) or writer.value(new BigDecimal(number.toString())).","If you control the Number subclass, ensure toString() returns a strictly RFC-8259-compliant number.","Validate the string against the JSON number grammar before calling value(Number).","For non-finite cases, handle separately (see error 177)."],"exampleFix":"// before\nwriter.value(customNumber); // throws if toString() is \"0x1A\"\n\n// after\nwriter.value(new BigDecimal(customNumber.toString()));","handlingStrategy":"validation","validationCode":"String s = number.toString();\nboolean valid = s.matches(\"-?(?:0|[1-9][0-9]*)(?:\\\\.[0-9]+)?(?:[eE][-+]?[0-9]+)?\");\nif (valid) {\n  writer.value(number);\n} else {\n  writer.value(new BigDecimal(s));\n}","typeGuard":"private static final Pattern JSON_NUMBER =\n    Pattern.compile(\"-?(?:0|[1-9][0-9]*)(?:\\\\.[0-9]+)?(?:[eE][-+]?[0-9]+)?\");\nstatic boolean isValidJsonNumberString(String s) {\n  return JSON_NUMBER.matcher(s).matches();\n}","tryCatchPattern":"try {\n  writer.value(number);\n} catch (IllegalArgumentException e) {\n  writer.value(number.doubleValue()); // fall back to a known-good Number\n}","preventionTips":["Convert custom Number subclasses to BigDecimal/Double before writing.","If you own the Number subclass, ensure toString() is RFC-8259 compliant.","Add tests with locale-formatted and hex strings to catch regressions."],"tags":["java","gson","jsonwriter","numeric","custom-number"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}