google/gson · error · NumberFormatException

Number has unsupported scale: {s}

Error message

Number has unsupported scale: {s}

What it means

Thrown by NumberLimits.parseBigDecimal as NumberFormatException when the absolute value of the parsed number's scale is >= 10,000. BigDecimal scale represents the number of digits to the right of the decimal point (negative means trailing zeros to the left). Extreme scales imply enormous internal int[] arrays and slow arithmetic, so Gson rejects them as a DoS/performance guard.

Source

Thrown at gson/src/main/java/com/google/gson/internal/NumberLimits.java:27

 */
public final class NumberLimits {
  private NumberLimits() {}

  private static final int MAX_NUMBER_STRING_LENGTH = 10_000;

  private static void checkNumberStringLength(String s) {
    if (s.length() > MAX_NUMBER_STRING_LENGTH) {
      throw new NumberFormatException("Number string too large: " + s.substring(0, 30) + "...");
    }
  }

  public static BigDecimal parseBigDecimal(String s) throws NumberFormatException {
    checkNumberStringLength(s);
    BigDecimal decimal = new BigDecimal(s);

    // Cast to long to avoid issues with abs when value is Integer.MIN_VALUE
    if (Math.abs((long) decimal.scale()) >= 10_000) {
      throw new NumberFormatException("Number has unsupported scale: " + s);
    }
    return decimal;
  }

  public static BigInteger parseBigInteger(String s) throws NumberFormatException {
    checkNumberStringLength(s);
    return new BigInteger(s);
  }
}

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Model the field as a String and validate/sanitize the exponent before numeric conversion.
  2. Cap or normalize the exponent: if the magnitude is implausible for your domain, reject the input.
  3. Prefer Double/Long targets when full arbitrary precision is not required, avoiding the BigDecimal path entirely.

Example fix

// before: huge exponent
gson.fromJson("1e100000", BigDecimal.class); // NumberFormatException

// after: read as string, validate exponent, then parse
String s = gson.fromJson(json, String.class);
if (s.matches(".*[eE][+-]?\d{5,}")) throw new IllegalArgumentException("scale too large");
BigDecimal v = new BigDecimal(s);
Defensive patterns

Strategy: validation

Validate before calling

static boolean scaleIsAcceptable(String s) {
  // reject exponents with magnitude >= 10000, or absurd decimal lengths
  java.util.regex.Matcher m = java.util.regex.Pattern.compile("[eE]([+-]?\\d+)").matcher(s);
  if (m.find()) {
    long exp = Long.parseLong(m.group(1));
    if (Math.abs(exp) >= 10_000) return false;
  }
  return s.length() <= 10_000;
}

Type guard

static boolean isReasonableBigDecimal(String s) {
  return scaleIsAcceptable(s);
}

Try / catch

try {
  NumberLimits.parseBigDecimal(s);
} catch (NumberFormatException e) {
  if (e.getMessage().contains("unsupported scale")) {
    // fall back to Double or reject
    return Double.parseDouble(s);
  } else throw e;
}

Prevention

When it happens

Trigger: Parsing a JSON number whose decimal-point offset is huge, e.g. '1e100000' (positive scale magnitude >= 10,000) or a literal with thousands of leading/trailing zeros after the decimal point. Reached when LazilyParsedNumber needs a BigDecimal (e.g. longValue()/intValue() overflow path) or when Gson parses into BigDecimal/BigInteger-backed fields.

Common situations: Scientific-notation payloads with exponents beyond +/-10,000; mis-typed identifiers/UUIDs/hashes modeled as numbers; adversarial input crafted to blow up BigDecimal memory.

Related errors


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