elastic/elasticsearch · error · IllegalArgumentException

max x cannot be less than min x

Error message

max x cannot be less than min x

What it means

Thrown by CartesianValidator.validateBBox when maxX < minX. Cartesian coordinates (flat x/y plane, no antimeridian) require the x-ordinates to be ordered; an inverted x-range is always invalid. This validator exists specifically because the default (geographic) policy allows minX > maxX for antimeridian-crossing envelopes, so cartesian usage needs an explicit stricter check.

Source

Thrown at libs/geo/src/main/java/org/elasticsearch/geometry/utils/CartesianValidator.java:44

 * Validator for cartesian (non-geographic) coordinates. Its one job today is
 * {@link #validateBBox(double, double, double, double)}: unlike geographic coordinates, cartesian coordinates
 * have no antimeridian-crossing concept, so a rectangle's x-ordinates must be consistent (maxX cannot be less
 * than minX), in addition to the same y-ordinate check ({@link GeographyValidator} also applies to geographic
 * coordinates. This is deliberately a separate class from {@link StandardValidator}, even though the two
 * currently look similar in scope: {@link StandardValidator} is CRS-agnostic and is relied on by real
 * geographic production code paths (e.g. {@code GeometryParser}) that must tolerate antimeridian-crossing
 * envelopes, so it cannot safely gain this check.
 */
public class CartesianValidator implements GeometryValidator {

    public static final GeometryValidator INSTANCE = new CartesianValidator();

    private CartesianValidator() {}

    @Override
    public void validateBBox(double minX, double maxX, double maxY, double minY) {
        if (maxX < minX) {
            throw new IllegalArgumentException("max x cannot be less than min x");
        }
        GeometryValidator.super.validateBBox(minX, maxX, maxY, minY);
    }

    @Override
    public void validate(Geometry geometry) {
        geometry.visit(new GeometryVisitor<Void, RuntimeException>() {

            @Override
            public Void visit(Circle circle) throws RuntimeException {
                return null;
            }

            @Override
            public Void visit(GeometryCollection<?> collection) throws RuntimeException {
                for (Geometry g : collection) {
                    g.visit(this);
                }

View on GitHub (pinned to db6a809a66)

Solutions

  1. If the data is geographic (lat/lon), use GeographyValidator instead — it intentionally does NOT check x-ordering.
  2. If the data is truly cartesian, reorder or normalize so minX <= maxX before validating.
  3. Pass arguments in the documented (minX, maxX, maxY, minY) order.

Example fix

// before (geographic data routed through cartesian validator)
CartesianValidator.INSTANCE.validateBBox(170, -170, 20, -20); // throws

// after
GeographyValidator.instance(true).validateBBox(170, -170, 20, -20); // antimeridian-crossing OK
Defensive patterns

Strategy: validation

Validate before calling

if (dataIsGeographic) {
    GeographyValidator.instance(ignoreZ).validateBBox(minX, maxX, maxY, minY);
} else {
    if (minX > maxX) throw new IllegalArgumentException("cartesian minX > maxX");
    CartesianValidator.INSTANCE.validateBBox(minX, maxX, maxY, minY);
}

Prevention

When it happens

Trigger: Calling `CartesianValidator.INSTANCE.validateBBox(minX, maxX, maxY, minY)` with minX > maxX, or routing a bbox through a code path that uses CartesianValidator when the data is geographic.

Common situations: Using the cartesian validator on data that is actually geographic (longitude can legitimately exceed the western bound when crossing the antimeridian); argument-order mistakes passing (maxX, minX); inverted envelopes coming from upstream computations.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/1964477155c7ca20. Report an issue: GitHub.