{"record":{"id":"532ae5b96b0de0bf","repo":"google/gson","slug":"failed-parsing-s-as-currency-at-path-path","errorCode":null,"errorMessage":"Failed parsing '${s}' as Currency; at path ${path}","messagePattern":"Failed parsing '(.+?)' as Currency; at path (.+?)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java","lineNumber":815,"sourceCode":"        }\n\n        @Override\n        public void write(JsonWriter out, UUID value) throws IOException {\n          out.value(value == null ? null : value.toString());\n        }\n      };\n\n  public static final TypeAdapterFactory UUID_FACTORY = newFactory(UUID.class, UUID);\n\n  public static final TypeAdapter<Currency> CURRENCY =\n      new TypeAdapter<Currency>() {\n        @Override\n        public Currency read(JsonReader in) throws IOException {\n          String s = in.nextString();\n          try {\n            return Currency.getInstance(s);\n          } catch (IllegalArgumentException e) {\n            throw new JsonSyntaxException(\n                \"Failed parsing '\" + s + \"' as Currency; at path \" + in.getPreviousPath(), e);\n          }\n        }\n\n        @Override\n        public void write(JsonWriter out, Currency value) throws IOException {\n          out.value(value.getCurrencyCode());\n        }\n      }.nullSafe();\n  public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY);\n\n  /**\n   * An abstract {@link TypeAdapter} for classes whose JSON serialization consists of a fixed set of\n   * integer fields. That is the case for {@link Calendar} and the legacy serialization of various\n   * {@code java.time} types.\n   */\n  abstract static class IntegerFieldsTypeAdapter<T> extends TypeAdapter<T> {\n    private final List<String> fields;","sourceCodeStart":797,"sourceCodeEnd":833,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L797-L833","documentation":"Thrown by Gson's Currency TypeAdapter when java.util.Currency.getInstance cannot resolve the JSON string as an ISO 4217 currency code. Currency.getInstance throws IllegalArgumentException for unknown codes, which Gson wraps as a JsonSyntaxException. Note this adapter is nullSafe but does NOT consume a JSON null token explicitly in nextString().","triggerScenarios":"Deserializing a field of type java.util.Currency from a JSON string that is not a valid ISO 4217 code: lowercase (\"usd\" instead of \"USD\"), a 3-letter code not in the JDK's currency list, a currency symbol like \"$\", or a numeric code as a string.","commonSituations":"Mixing currency symbols ($) with ISO codes; receiving locale-formatted currency; new or unofficial ISO 4217 codes not yet in the running JDK's currency list; case-sensitive data sources emitting lowercase codes.","solutions":["Ensure the JSON value is an uppercase ISO 4217 code (e.g. \"USD\", \"EUR\").","Update the JDK / currency table (JDK holds the list in <jdk>/lib/currency.data) or run on a current JDK release so newer codes are recognized.","Register a custom TypeAdapter<Currency> that uppercases the input and maps known aliases/symbols to Currency.getInstance codes.","If only the symbol is available, deserialize as String and resolve through a lookup table in your domain code."],"exampleFix":"// before\npublic class Price { public Currency currency; }\n// JSON: {\"currency\":\"usd\"} -> fails (lowercase)\n\n// after: normalize case with a custom adapter\nGson g = new GsonBuilder()\n  .registerTypeHierarchyAdapter(Currency.class, new TypeAdapter<Currency>() {\n    public Currency read(JsonReader in) throws IOException {\n      String s = in.nextString().trim().toUpperCase(Locale.ROOT);\n      return Currency.getInstance(s);\n    }\n    public void write(JsonWriter out, Currency v) throws IOException { out.value(v.getCurrencyCode()); }\n  }).create();","handlingStrategy":"validation","validationCode":"private static final Set<String> ISO4217 =\n  Set.of(\"USD\",\"EUR\",\"GBP\",\"JPY\",\"CHF\",\"CAD\",\"AUD\",\"CNY\",\"INR\",\"BRL\",\"MXN\"); // extend as needed\nString raw = jsonNode.get(\"currency\").getAsString();\nif (raw == null || !ISO4217.contains(raw.trim().toUpperCase(Locale.ROOT))) {\n  throw new IllegalArgumentException(\"Unsupported currency code: \" + raw);\n}\n// or rely on Currency.getAvailableCurrencies() at startup","typeGuard":null,"tryCatchPattern":"try {\n  return gson.fromJson(json, Price.class);\n} catch (JsonSyntaxException e) {\n  if (e.getMessage().contains(\"as Currency\")) {\n    throw new IllegalArgumentException(\"Unknown currency code\", e);\n  }\n  throw e;\n}","preventionTips":["Whitelist allowed currency codes from Currency.getAvailableCurrencies() at startup.","Normalize case to uppercase before parsing.","Never accept currency symbols ($) at the data layer; map them to ISO codes at ingestion.","Run on a current JDK so newer ISO 4217 codes are recognized."],"tags":["gson","parsing","currency","iso-4217","json-syntax-exception","type-adapter"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}