google/gson · error · JsonSyntaxException

Failed parsing ' ' as BigInteger; at path

Error message

Failed parsing '${s}' as BigInteger; at path ${path}

What it means

Thrown by Gson's built-in BigInteger TypeAdapter when the JSON value cannot be parsed by NumberLimits.parseBigInteger. Gson reads the token as a string (so it accepts both JSON numbers and JSON strings) and delegates to BigInteger parsing; if the text contains non-numeric characters, exponents in unsupported form, or is empty, a NumberFormatException is wrapped as a JsonSyntaxException pinpointing the offending path.

Solutions

  1. Inspect the 'at path' location in the error and fix the source JSON so the value is an integer string like "123" or a JSON integer number.
  2. If the value legitimately may contain decimals/commas, change the Java field to BigDecimal or String and convert manually.
  3. Register a custom TypeAdapter<BigInteger> that strips thousands separators or rounds decimals before calling new BigInteger(cleaned).
  4. Sanitize input at the API boundary before handing the JSON to Gson.

Example fix

// before
public class Account { public BigInteger balanceMicros; }
// JSON: {"balanceMicros":"1,000.00"} -> fails

// after: use BigDecimal or sanitize
public class Account {
  public String balanceMicros; // or BigDecimal
  public BigInteger asBigInteger() { return new BigInteger(balanceMicros.replaceAll("[^0-9-]","")); }
}

// or custom adapter:
Gson g = new GsonBuilder()
  .registerTypeHierarchyAdapter(BigInteger.class, new TypeAdapter<BigInteger>() {
    public BigInteger read(JsonReader in) throws IOException {
      String s = in.nextString().replaceAll("[,]","");
      return new BigInteger(s);
    }
    public void write(JsonWriter out, BigInteger v) throws IOException { out.value(v); }
  }).create();
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern BIG_INT = Pattern.compile("[+-]?\\d+");
String raw = jsonNode.get("balanceMicros").getAsString();
if (!BIG_INT.matcher(raw.trim()).matches()) {
  throw new IllegalArgumentException("Not a BigInteger: " + raw);
}
// now safe to call fromJson or new BigInteger(raw.trim())

Try / catch

try {
  return gson.fromJson(json, HasBigInt.class);
} catch (JsonSyntaxException e) {
  if (e.getMessage().contains("as BigInteger")) {
    // log offending path, default, or reject the record
    throw new IllegalArgumentException("Invalid BigInteger in payload", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Deserializing JSON into a field/element of type java.math.BigInteger (or Map<BigInteger, ...>) where the JSON value is non-numeric (e.g. "abc", "", "NaN", "1.5" with fractional part that BigInteger rejects, or an object/array token that the reader coerced). Also triggered when a JSON number has a floating exponent/sign that BigInteger cannot represent.

Common situations: Sending a decimal/floating value like 3.14 into a BigInteger field; receiving IDs from an upstream service that quotes numbers as strings with stray characters; locale-specific formatting (commas as thousands separators e.g. "1,000"); mistakenly mapping a BigInteger field onto a JSON object.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/7cd05ed68288e907. Report an issue: GitHub.

Appendix: source

Thrown at gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java:619

        }
      };

  public static final TypeAdapterFactory BIG_DECIMAL_FACTORY =
      newFactory(BigDecimal.class, BIG_DECIMAL);

  public static final TypeAdapter<BigInteger> BIG_INTEGER =
      new TypeAdapter<BigInteger>() {
        @Override
        public BigInteger read(JsonReader in) throws IOException {
          if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
          }
          String s = in.nextString();
          try {
            return NumberLimits.parseBigInteger(s);
          } catch (NumberFormatException e) {
            throw new JsonSyntaxException(
                "Failed parsing '" + s + "' as BigInteger; at path " + in.getPreviousPath(), e);
          }
        }

        @Override
        public void write(JsonWriter out, BigInteger value) throws IOException {
          out.value(value);
        }
      };

  public static final TypeAdapterFactory BIG_INTEGER_FACTORY =
      newFactory(BigInteger.class, BIG_INTEGER);

  public static final TypeAdapter<LazilyParsedNumber> LAZILY_PARSED_NUMBER =
      new TypeAdapter<LazilyParsedNumber>() {
        // Normally users should not be able to access and deserialize LazilyParsedNumber because
        // it is an internal type, but implement this nonetheless in case there are legit corner
        // cases where this is possible

View on GitHub (pinned to 310ac341f2)