{"id":"652c3579e3863535","repo":"google/gson","slug":"failed-parsing-s-as-bigdecimal-at-path","errorCode":null,"errorMessage":"Failed parsing '\" + s + \"' as BigDecimal; at path \" + in.getPreviousPath()","messagePattern":"Failed parsing '\" \\+ s \\+ \"' as BigDecimal; at path \" \\+ in\\.getPreviousPath\\(\\)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java","lineNumber":591,"sourceCode":"        @Override\n        public void write(JsonWriter out, String value) throws IOException {\n          out.value(value);\n        }\n      };\n\n  public static final TypeAdapter<BigDecimal> BIG_DECIMAL =\n      new TypeAdapter<BigDecimal>() {\n        @Override\n        public BigDecimal read(JsonReader in) throws IOException {\n          if (in.peek() == JsonToken.NULL) {\n            in.nextNull();\n            return null;\n          }\n          String s = in.nextString();\n          try {\n            return NumberLimits.parseBigDecimal(s);\n          } catch (NumberFormatException e) {\n            throw new JsonSyntaxException(\n                \"Failed parsing '\" + s + \"' as BigDecimal; at path \" + in.getPreviousPath(), e);\n          }\n        }\n\n        @Override\n        public void write(JsonWriter out, BigDecimal value) throws IOException {\n          out.value(value);\n        }\n      };\n\n  public static final TypeAdapterFactory BIG_DECIMAL_FACTORY =\n      newFactory(BigDecimal.class, BIG_DECIMAL);\n\n  public static final TypeAdapter<BigInteger> BIG_INTEGER =\n      new TypeAdapter<BigInteger>() {\n        @Override\n        public BigInteger read(JsonReader in) throws IOException {\n          if (in.peek() == JsonToken.NULL) {","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L573-L609","documentation":"Thrown by Gson's built-in BigDecimal TypeAdapter when the JSON token cannot be parsed by NumberLimits.parseBigDecimal. Gson reads the value as a string then delegates to BigDecimal parsing, so any non-numeric, malformed, or locale-specific number (e.g. with a comma) triggers a NumberFormatException that is wrapped into a JsonSyntaxException. The 'at path' suffix identifies the offending location in the JSON tree.","triggerScenarios":"Deserializing a JSON value into a BigDecimal field/element where the source string is not valid BigDecimal syntax (letters, multiple dots, thousands separators like '1,234.5', trailing spaces, empty string, or a JSON boolean/object).","commonSituations":"European locale data with decimal commas, upstream API returning null-as-empty-string, mismatch between producer locale and consumer expectations, numbers in scientific notation that exceed configured limits, or a field typed as BigDecimal but populated with a currency symbol.","solutions":["Inspect the 'at path' location in your JSON and correct the offending value to plain numeric syntax (dot decimal, no separators).","Sanitize the string before Gson deserialization, e.g. strip currency symbols and replace commas with dots.","Register a custom TypeAdapter<BigDecimal> that pre-cleans or falls back gracefully on malformed input.","Use Gson's setLenient()/object-mapping to accept the value as String first, then convert manually."],"exampleFix":"// before\nGson gson = new Gson();\nBigDecimal price = gson.fromJson(json, BigDecimal.class);\n\n// after: tolerate locale-formatted numbers\nGson gson = new GsonBuilder()\n    .registerTypeHierarchyAdapter(BigDecimal.class, new JsonDeserializer<BigDecimal>() {\n        @Override public BigDecimal deserialize(JsonElement j, Type t, JsonDeserializationContext c) {\n            String s = j.getAsString().replace(\".\", \"\").replace(\",\", \".\").trim();\n            return s.isEmpty() ? BigDecimal.ZERO : new BigDecimal(s);\n        }\n    }).create();","handlingStrategy":"validation","validationCode":"boolean isParsableBigDecimal(String s) {\n  if (s == null || s.isEmpty()) return false;\n  try { new BigDecimal(s); return true; } catch (NumberFormatException e) { return false; }\n}","typeGuard":"static boolean isBigDecimalString(JsonElement el) {\n  return el != null && el.isJsonPrimitive() && el.getAsJsonPrimitive().isString()\n    && el.getAsString().matches(\"[+-]?(\\\\d+(\\\\.\\\\d+)?|\\\\.\\\\d+)\");\n}","tryCatchPattern":"try {\n  BigDecimal v = gson.fromJson(json, BigDecimal.class);\n} catch (JsonSyntaxException e) {\n  // log the path from e.getMessage(), fall back to null or a sentinel\n}","preventionTips":["Validate numeric strings with a regex or trial-parse before handing them to Gson.","Define a schema/contract for BigDecimal fields (plain decimal, dot separator, no symbols).","Register a single normalization TypeAdapter<BigDecimal> at Gson construction rather than patching call sites."],"tags":["gson","deserialization","big-decimal","json","number-parsing"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}