JsonPath: large negative JSON numbers overflow to -Infinity (sign-blind float/double selection)

Author: haskiindahouseCreated Jul 21, 2026Updated Jul 21, 2026

Description

Under the default JsonPath configuration (NumberReturnType.FLOAT_AND_DOUBLE, no config needed), JsonPath.get(path) chooses between float and double for a non-integer number with a sign-blind upper-bound test. A positive value above Float.MAX_VALUE (~3.4e38) stays a double. A negative value of the same magnitude falls into the float branch, where BigDecimal.floatValue() overflows to Float.NEGATIVE_INFINITY. The valid finite JSON number -1e40 comes back as -Infinity, with no exception and no warning.

JSON: {"pos": 1e40, "neg": -1e40}
get("pos") = 1e40  -> java.lang.Double = 1.0E40      (correct)
get("neg") = -1e40 -> java.lang.Float  = -Infinity   (finite value destroyed)

Same magnitude, opposite sign, divergent outcome. rest-assured's own XmlPath.getDouble returns the correct -1.0E40 for the identical value.

rest-assured version

  • Reproduced on released io.rest-assured:json-path:5.5.6 (Maven Central) and on master HEAD eeed4998 (6.0.2-SNAPSHOT). Present unchanged from the Groovy 5.x form through the migrated Java form.
  • Java 24 (Temurin 24.0.1). Default JsonPath config.

Steps to reproduce

Minimal, self-contained (json-path + Groovy on the classpath):

java
import io.restassured.path.json.JsonPath;

public class Repro {
    public static void main(String[] a) {
        JsonPath jp = JsonPath.from("{\"pos\": 1e40, \"neg\": -1e40}");
        System.out.println("get(pos)       = " + jp.get("pos") + " (" + jp.get("pos").getClass().getSimpleName() + ")");
        System.out.println("get(neg)       = " + jp.get("neg") + " (" + jp.get("neg").getClass().getSimpleName() + ")");
        System.out.println("getDouble(neg) = " + jp.getDouble("neg"));
    }
}

Output:

get(pos)       = 1.0E40 (Double)
get(neg)       = -Infinity (Float)     <-- BUG
getDouble(neg) = -Infinity             <-- inherits the corruption

A boundary sweep pins the asymmetry at Float.MAX_VALUE. Both signs agree while |x| <= Float.MAX_VALUE. The divergence starts the instant |x| > Float.MAX_VALUE, and only on the negative side: -3.5e38, -4.0e38, -1e40 all return -Infinity while their positive twins return Double values.

Expected

get("neg") / getDouble("neg") return the finite -1.0E40 (as a Double), symmetric with the positive case and matching com.jayway.jsonpath 2.9.0, raw Double.parseDouble, and rest-assured's own XmlPath.getDouble.

Actual

-Infinity. A valid finite number overflows to negative infinity with no error.

Root cause

json-path/src/main/java/io/restassured/internal/path/json/ConfigurableJsonSlurper.java (HEAD eeed4998), inside the BigDecimal to float/double conversion:

java
if (numberReturnType == NumberReturnType.DOUBLE
        || decimal.compareTo(BigDecimal.valueOf(Float.MAX_VALUE)) > 0) {
    result = decimal.doubleValue();
} else {
    result = decimal.floatValue();   // overflows to +/-Infinity for |x| > Float.MAX_VALUE
}

The guard tests the positive upper bound alone: decimal.compareTo(BigDecimal.valueOf(Float.MAX_VALUE)) > 0. Every negative decimal compares below Float.MAX_VALUE, so the test fails and control reaches the float branch, where BigDecimal.floatValue() returns Float.NEGATIVE_INFINITY for out-of-range magnitudes. The released 5.5.6 Groovy form (ConfigurableJsonSlurper.groovy, if (result > Float.MAX_VALUE || ...)) has the same defect. Only the default FLOAT_AND_DOUBLE path is affected; DOUBLE and BIG_DECIMAL behave.

Suggested fix

Compare magnitude instead of the signed value:

java
if (numberReturnType == NumberReturnType.DOUBLE
        || decimal.abs().compareTo(BigDecimal.valueOf(Float.MAX_VALUE)) > 0) {
    result = decimal.doubleValue();
} else {
    result = decimal.floatValue();
}

(Groovy 5.x form: if (result.abs() > Float.MAX_VALUE || numberReturnType == NumberReturnType.DOUBLE).)


Found via property-based & differential bug-hunting, part of an effort to scale PBT (DepTyCheck-based) testing across the OSS ecosystem.

If this is intended / by-design: I'm really sorry, please just close it — no need to flag or ban me. I'm trying to scale property-based testing across the whole ecosystem and my publishing agents may have gotten this one wrong. I read every issue and follow up on each.

Source: rest-assured/rest-assured