{"record":{"id":"8e3398544d7a3e4f","repo":"google/gson","slug":"string-contains-non-ascii-characters-s-at-path","errorCode":null,"errorMessage":"String contains non-ASCII characters: ${s} at path ${path}","messagePattern":"String contains non-ASCII characters: (.+?) at path (.+?)","errorType":"exception","errorClass":"MalformedJsonException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java","lineNumber":431,"sourceCode":"  }\n\n  private String locationString() {\n    return \" at path \" + getPath();\n  }\n\n  /** Returns whether every character of {@code s} is ASCII (code point at most 127). */\n  public static boolean isAllAscii(String s) {\n    for (int i = 0; i < s.length(); i++) {\n      if (s.charAt(i) > 127) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  private void validateAscii(String s) throws MalformedJsonException {\n    if (!isAllAscii(s)) {\n      throw new MalformedJsonException(\n          \"String contains non-ASCII characters: \" + s + locationString());\n    }\n  }\n\n  /** Creates a {@link NumberFormatException} whose message includes the current path. */\n  private NumberFormatException numberFormatException(String message, NumberFormatException cause) {\n    NumberFormatException exception = new NumberFormatException(message + locationString());\n    exception.initCause(cause);\n    return exception;\n  }\n}\n","sourceCodeStart":413,"sourceCodeEnd":443,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/JsonTreeReader.java#L413-L443","documentation":"JsonTreeReader (Gson's reader over an in-memory JsonElement tree) calls validateAscii() inside nextInt() and nextLong() when the current token is a STRING being coerced to a number. If any character has a code point above 127 (e.g. full-width CJK digits like '１２３'), Gson throws MalformedJsonException because such strings cannot be reliably parsed as a Java integer. The guard exists because non-ASCII numeric characters would otherwise yield silent, wrong numeric results.","triggerScenarios":"Deserializing a JsonElement tree into an int/long field where the JSON value is a string token containing non-ASCII characters; calling nextInt()/nextLong() directly on a JsonReader wrapping a JsonPrimitive string with Unicode digits; data produced by CJK-localized systems emitting full-width numerals.","commonSituations":"Internationalized data from Japanese/Chinese/Korean locales using full-width digits; copy-paste from office suites that auto-convert ASCII digits to typographic Unicode forms; JSON received from systems that localize number formatting.","solutions":["Normalize the offending string to ASCII before parsing, e.g. java.text.Normalizer.normalize(s, Normalizer.Form.NFKC) to fold full-width digits to ASCII","Write a custom TypeAdapter<Integer>/<Long> (registered via GsonBuilder.registerTypeAdapter) that pre-normalizes the string","Fix the data at its origin to emit ASCII digit characters (0-9)"],"exampleFix":"// before - throws on JsonPrimitive(\"１２３\")\nint v = jsonElement.getAsInt();\n\n// after - normalize full-width digits to ASCII first\nString s = jsonElement.getAsString();\ns = java.text.Normalizer.normalize(s, java.text.Normalizer.Form.NFKC);\nint v = Integer.parseInt(s);","handlingStrategy":"validation","validationCode":"// Before parsing a string token as int/long, verify ASCII\nimport com.google.gson.internal.bind.JsonTreeReader;\n\nString s = jsonPrimitive.getAsString();\nif (!JsonTreeReader.isAllAscii(s)) {\n    s = java.text.Normalizer.normalize(s, java.text.Normalizer.Form.NFKC);\n}\nint value = Integer.parseInt(s); // safe now","typeGuard":null,"tryCatchPattern":"try {\n  int v = gson.fromJson(jsonElement, Integer.class);\n} catch (com.google.gson.stream.MalformedJsonException e) {\n  // message indicates non-ASCII; normalize source and retry, or fall back\n}","preventionTips":["Normalize all incoming numeric strings to ASCII (NFKC) at the ingestion boundary","Validate that numeric source fields contain only ASCII digits before they reach Gson","Add unit tests with full-width and locale-specific digit inputs"],"tags":["json","deserialization","unicode","ascii","number-parsing"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}