google/gson · error · JsonSyntaxException
Failed parsing '" + s + "' as Currency; at path " + in.getPr
Error message
Failed parsing '" + s + "' as Currency; at path " + in.getPreviousPath()
What it means
Gson's Currency TypeAdapter calls Currency.getInstance(s), which only accepts ISO 4217 currency codes. Any string that is not a recognized 3-letter code throws IllegalArgumentException, wrapped as JsonSyntaxException. The adapter is nullSafe so null is handled, but malformed strings are not.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java:813
}
@Override
public void write(JsonWriter out, UUID value) throws IOException {
out.value(value == null ? null : value.toString());
}
};
public static final TypeAdapterFactory UUID_FACTORY = newFactory(UUID.class, UUID);
public static final TypeAdapter<Currency> CURRENCY =
new TypeAdapter<Currency>() {
@Override
public Currency read(JsonReader in) throws IOException {
String s = in.nextString();
try {
return Currency.getInstance(s);
} catch (IllegalArgumentException e) {
throw new JsonSyntaxException(
"Failed parsing '" + s + "' as Currency; at path " + in.getPreviousPath(), e);
}
}
@Override
public void write(JsonWriter out, Currency value) throws IOException {
out.value(value.getCurrencyCode());
}
}.nullSafe();
public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY);
/**
* An abstract {@link TypeAdapter} for classes whose JSON serialization consists of a fixed set of
* integer fields. That is the case for {@link Calendar} and the legacy serialization of various
* {@code java.time} types.
*/
abstract static class IntegerFieldsTypeAdapter<T> extends TypeAdapter<T> {
private final List<String> fields;View on GitHub (pinned to 8b8628c656)
Solutions
- Normalize the value to an uppercase ISO 4217 code before deserialization.
- Register a custom TypeAdapter<Currency> that uppercases the string and maps legacy codes to their successors.
- Correct the upstream producer to emit valid ISO 4217 codes.
Example fix
// before
Currency c = gson.fromJson("\"usd\"", Currency.class);
// after
Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(Currency.class, new JsonDeserializer<Currency>() {
@Override public Currency deserialize(JsonElement j, Type t, JsonDeserializationContext c) {
return Currency.getInstance(j.getAsString().toUpperCase(Locale.ROOT));
}
}).create(); Defensive patterns
Strategy: validation
Validate before calling
boolean isParsableCurrency(String s) {
if (s == null || s.length() != 3) return false;
try { Currency.getInstance(s.toUpperCase(Locale.ROOT)); return true; } catch (IllegalArgumentException e) { return false; }
} Type guard
static boolean isIsoCurrency(String s) {
return s != null && s.matches("[A-Za-z]{3}") && Currency.getAvailableCurrencies().stream().anyMatch(c -> c.getCurrencyCode().equalsIgnoreCase(s));
} Try / catch
try {
Currency c = gson.fromJson(json, Currency.class);
} catch (JsonSyntaxException e) {
// map legacy/custom codes, or reject the record
} Prevention
- Upper-case and length-check currency strings at the boundary.
- Maintain a mapping table for legacy currency codes if your data contains them.
- Register a normalization TypeAdapter<Currency> globally.
When it happens
Trigger: Deserializing a JSON string into a Currency field where the value is not a valid ISO 4217 code (wrong length, lowercase, deprecated code like 'ITL', or a symbol like '$').
Common situations: Producer emits lowercase 'usd', a locale-specific symbol, a deprecated/legacy currency code, or a custom code that Currency.getInstance does not recognize.
Related errors
- duplicate key: {key}
- Expecting number, got: " + jsonToken + "; at path " + in.get
- Unexpected token: " + peeked
- Failed parsing '" + s + "' as BigDecimal; at path " + in.get
- Failed parsing '" + s + "' as BigInteger; at path " + in.get
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/70e0f7704eec7118.json.
Report an issue: GitHub.