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
- Model the field as a String and validate/sanitize the exponent before numeric conversion.
- Cap or normalize the exponent: if the magnitude is implausible for your domain, reject the input.
- 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
- Model fields with extreme precision needs as Strings and bound the exponent.
- Prefer Double/Long when arbitrary precision is unnecessary.
- Sanitize JSON before parsing to reject pathological exponents.
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
- Number string too large: {value}...
- Deserialization is unsupported
- Invalid bitset value " + intValue + ", expected 0 or 1; at p
- Lossy conversion from " + intValue + " to byte; at path " +
- Lossy conversion from " + intValue + " to short; at path " +
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/4a75d0107695a3df.json.
Report an issue: GitHub.