microg/GmsCore · error · IllegalStateException

Position already set using position()

Error message

Position already set using position()

What it means

GroundOverlayOptions.positionFromBounds(LatLngBounds) throws IllegalStateException when the position was already set via position(LatLng, float) or position(LatLng, float, float). Only one positioning strategy is allowed per overlay; the builder detects an existing anchor location and rejects the bounds-based positioning. Note the converse error, 205, is thrown by position() when bounds were set first.

Source

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

        this.location = location;
        this.width = width;
        return this;
    }

    /**
     * Specifies the position for this ground overlay. When rendered, the image will be scaled to
     * fit the bounds (i.e., its proportions will not necessarily be preserved).
     *
     * @param bounds a {@link LatLngBounds} in which to place the ground overlay
     * @return this {@link GroundOverlayOptions} object with a new position set.
     * @throws IllegalStateException if the position was already set using
     *                               {@link #position(LatLng, float)} or
     *                               {@link #position(LatLng, float, float)}
     */
    public GroundOverlayOptions positionFromBounds(LatLngBounds bounds)
            throws IllegalStateException {
        if (location != null)
            throw new IllegalStateException("Position already set using position()");
        this.bounds = bounds;
        return this;
    }

    /**
     * Specifies the transparency of the ground overlay. The default transparency is {code 0}
     * (opaque).
     *
     * @param transparency a float in the range {@code [0..1]} where {@code 0} means that the
     *                     ground overlay is opaque and {code 1} means that the ground overlay is
     *                     transparent
     * @return this {@link GroundOverlayOptions} object with a new visibility setting.
     * @throws IllegalArgumentException if the transparency is outside the range [0..1].
     */
    public GroundOverlayOptions transparency(float transparency) throws IllegalArgumentException {
        if (transparency < 0 || transparency > 1)
            throw new IllegalArgumentException("transparency must be in range [0..1]");
        this.transparency = transparency;

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Remove the earlier position(...) call when using positionFromBounds(...).
  2. Construct a fresh GroundOverlayOptions for each overlay instead of reusing and reconfiguring one builder.
  3. Structure the builder setup as exclusive branches (if bounds -> positionFromBounds else position).

Example fix

// before
GroundOverlayOptions opts = new GroundOverlayOptions()
    .position(center, 1000f)
    .positionFromBounds(bounds); // IllegalStateException

// after
GroundOverlayOptions opts = new GroundOverlayOptions()
    .positionFromBounds(bounds); // choose one strategy only
Defensive patterns

Strategy: validation

Validate before calling

if (alreadyCalledPosition) { /* do not call positionFromBounds(...) */ }

Type guard

boolean isBoundsFree(GroundOverlayOptions o) { return !o.getPositionSet(); } // track it yourself with a flag

Try / catch

try {
    options.positionFromBounds(bounds);
} catch (IllegalStateException e) {
    // already positioned via position(); keep that strategy
}

Prevention

When it happens

Trigger: Calling positionFromBounds(...) after position(...) on the same GroundOverlayOptions instance, typically in fluent chains or shared builders configured by multiple code paths.

Common situations: Refactoring an overlay from explicit dimensions to bounds-fitting without removing the old position() call; a common options factory method where callers additionally set a position; retry/reconfiguration logic that re-applies positioning on an existing builder.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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