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

  1. Sanitize the value before writing: write null, 0, or a sentinel when !Double.isFinite(value), e.g. writer.value(Double.isFinite(d) ? d : null).
  2. If emitting raw NaN/Infinity tokens is acceptable for your consumer, call writer.setStrictness(Strictness.LENIENT) before writing.
  3. In a custom JsonSerializer, normalize the source field (replace NaN/infinity with null or a default) rather than forwarding it to JsonWriter.
  4. 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

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


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