microg/GmsCore · error · IllegalArgumentException

latitude of northeast corner must not be lower than latitude

Error message

latitude of northeast corner must not be lower than latitude of southwest corner

What it means

The LatLngBounds(southwest, northeast) constructor throws IllegalArgumentException when northeast.latitude is lower than southwest.latitude. Bounds must be a valid rectangle with the northeast corner geographically north of (or equal to) the southwest corner. Longitude is not validated the same way (it may wrap), but the latitude ordering is mandatory.

Source

Thrown at play-services-maps/src/main/java/com/google/android/gms/maps/model/LatLngBounds.java:70

     * Creates a new bounds based on a southwest and a northeast corner.
     * <p/>
     * The bounds conceptually includes all points where:
     * <ul>
     * <li>the latitude is in the range [northeast.latitude, southwest.latitude];</li>
     * <li>the longitude is in the range [southwest.longtitude, northeast.longitude]
     * if southwest.longtitude ≤ northeast.longitude; and</li>
     * <li>the longitude is in the range [southwest.longitude, 180) ∪ [-180, northeast.longitude]
     * if southwest.longtitude > northeast.longitude.</li>
     * </ul>
     *
     * @param southwest southwest corner
     * @param northeast northeast corner
     * @throws IllegalArgumentException if the latitude of the northeast corner is below the
     *                                  latitude of the southwest corner.
     */
    public LatLngBounds(LatLng southwest, LatLng northeast) throws IllegalArgumentException {
        if (northeast.latitude < southwest.latitude)
            throw new IllegalArgumentException("latitude of northeast corner must not be" +
                    " lower than latitude of southwest corner");
        this.southwest = southwest;
        this.northeast = northeast;
    }

    /**
     * Creates a new builder.
     */
    public Builder builder() {
        return new Builder();
    }

    /**
     * Returns whether this contains the given {@link LatLng}.
     *
     * @param point the {@link LatLng} to test
     * @return {@code true} if this contains the given point; {@code false} if not.
     */

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Normalize the corners before constructing: sw = new LatLng(min(lat1,lat2), ...), ne = new LatLng(max(lat1,lat2), ...).
  2. Prefer LatLngBounds.builder() with include(point) for each point — it maintains correct ordering automatically.
  3. When receiving bounds from external input, validate/swap corners: if (ne.latitude < sw.latitude) swap the latitudes.

Example fix

// before
LatLngBounds bounds = new LatLngBounds(pointA, pointB); // may be unordered

// after
LatLngBounds bounds = new LatLngBounds.Builder()
    .include(pointA)
    .include(pointB)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

double sLat = Math.min(a.latitude, b.latitude);
double nLat = Math.max(a.latitude, b.latitude);
// build corners from ordered latitudes

Type guard

boolean isOrdered(LatLng sw, LatLng ne) { return ne.latitude >= sw.latitude; }

Try / catch

try {
    LatLngBounds b = new LatLngBounds(sw, ne);
} catch (IllegalArgumentException e) {
    LatLngBounds b = new LatLngBounds(
        new LatLng(Math.min(sw.latitude, ne.latitude), sw.longitude),
        new LatLng(Math.max(sw.latitude, ne.latitude), ne.longitude));
}

Prevention

When it happens

Trigger: Calling new LatLngBounds(sw, ne) where ne.latitude < sw.latitude — e.g. corners computed independently from two arbitrary points, coordinates swapped, or bounds accumulated by naive min/max on mismatched axes.

Common situations: Building bounds from two user-selected points without ordering them (the user may drag a selection 'south-up'); deserializing bounds from an API where corners arrive unordered; computing a bounds from a path in the wrong order; using include() instead avoids this entirely.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/702afe41a1ea6aa6. Report an issue: GitHub.