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

  1. Normalize the value to an uppercase ISO 4217 code before deserialization.
  2. Register a custom TypeAdapter<Currency> that uppercases the string and maps legacy codes to their successors.
  3. 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

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


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/70e0f7704eec7118.json. Report an issue: GitHub.