google/gson · error · IllegalArgumentException
Numeric values must be finite, but was " + string
Error message
Numeric values must be finite, but was " + string
What it means
Thrown by JsonWriter.value(Number) when the number's toString() is "NaN", "Infinity", or "-Infinity" and the writer is not in Strictness.LENIENT mode (default is LEGACY_STRICT). RFC 8259 JSON forbids these non-finite values, so Gson refuses to serialize them to keep output spec-compliant. The check only fires for Float/Double (and other types whose toString can yield those literals); integral types are trusted. Switching the writer to LENIENT lets NaN/Infinity through verbatim.
Source
Thrown at gson/src/main/java/com/google/gson/stream/JsonWriter.java:646
* @throws IllegalArgumentException if the value is NaN or Infinity and this writer is not {@link
* #setStrictness(Strictness) lenient}; or if the {@code toString()} result is not a valid
* JSON number.
*/
@CanIgnoreReturnValue
public JsonWriter value(Number value) throws IOException {
if (value == null) {
return nullValue();
}
writeDeferredName();
String string = value.toString();
Class<? extends Number> numberClass = value.getClass();
if (!alwaysCreatesValidJsonNumber(numberClass)) {
// Validate that string is valid before writing it directly to JSON output
if (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN")) {
if (strictness != Strictness.LENIENT) {
throw new IllegalArgumentException("Numeric values must be finite, but was " + string);
}
} else if (numberClass != Float.class
&& numberClass != Double.class
&& !VALID_JSON_NUMBER_PATTERN.matcher(string).matches()) {
throw new IllegalArgumentException(
"String created by " + numberClass + " is not a valid JSON number: " + string);
}
}
beforeValue();
out.append(string);
return this;
}
/**
* Encodes {@code null}.
*
* @return this writer.View on GitHub (pinned to 8b8628c656)
Solutions
- Sanitize the value before writing: write null, 0, or a sentinel when !Double.isFinite(value), e.g. writer.value(Double.isFinite(d) ? d : null).
- If emitting raw NaN/Infinity tokens is acceptable for your consumer, call writer.setStrictness(Strictness.LENIENT) before writing.
- In a custom JsonSerializer, normalize the source field (replace NaN/infinity with null or a default) rather than forwarding it to JsonWriter.
- Register a TypeAdapter for Double/Float that coerces non-finite values to null, so the fix is centralized.
Example fix
// before
Double ratio = computeRatio(); // may be NaN or Infinity
jsonWriter.value(ratio);
// after
Double ratio = computeRatio();
if (ratio != null && Double.isFinite(ratio)) {
jsonWriter.value(ratio);
} else {
jsonWriter.nullValue();
} Defensive patterns
Strategy: validation
Validate before calling
// Run before writer.value(Number)
public static Number sanitizeNumber(Number n) {
if (n == null) return null;
if (n instanceof Double d && !Double.isFinite(d)) return null;
if (n instanceof Float f && !Float.isFinite(f)) return null;
return n;
}
// usage: writer.value(sanitizeNumber(d)); Type guard
import java.util.Objects;
/** True only for finite Double/Float values safe for strict JSON. */
public static boolean isFiniteJsonNumber(Number n) {
if (n == null) return false;
if (n instanceof Double d) return Double.isFinite(d);
if (n instanceof Float f) return Float.isFinite(f);
return true; // integral / BigDecimal etc. are always finite
} Try / catch
try {
writer.value(d);
} catch (IllegalArgumentException e) {
// non-finite number in strict mode; emit null instead
writer.nullValue();
} Prevention
- Never let Double/Float fields default to NaN; initialize to null or 0.0.
- Centralize numeric serialization through a TypeAdapter that coerces non-finite values.
- Assert Double.isFinite(x) at the boundary where the value is computed (division, parsing).
- If NaN/Infinity is semantically valid for your domain, set the writer to Strictness.LENIENT explicitly and document why.
When it happens
Trigger: Calling jsonWriter.value(Double.NaN), jsonWriter.value(Double.POSITIVE_INFINITY), jsonWriter.value(Float.NEGATIVE_INFINITY), or passing a Double/Float variable that is NaN/infinite while strictness is LEGACY_STRICT (default) or STRICT. Also reached indirectly when a TypeAdapter / JsonSerializer calls writer.value(d) on a computed double that overflowed to infinity (e.g. 1.0/0.0) or an unset field defaulting to NaN.
Common situations: Serializing scientific/financial data with division-by-zero producing infinity; logging or telemetry POJOs whose double fields are uninitialized to NaN; migrating from older Gson where setLenient(true) was used and the 2.11+ Strictness API reset it to LEGACY_STRICT; custom serializers that forward raw doubles without sanitizing; JSON-RPC/REST endpoints that must never emit non-finite numbers to JS clients (where NaN becomes null).
Related errors
- String created by " + numberClass + " is not a valid JSON nu
- JSON forbids NaN and infinities: {value}
- JSON must have only one top-level value.
- String contains non-ASCII characters: {s}{location}
- Expecting number, got: " + jsonToken + "; at path " + in.get
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/fdd88d367c255bfc.json.
Report an issue: GitHub.