microg/GmsCore · error · IllegalStateException
Position already set using positionFromBounds()
Error message
Position already set using positionFromBounds()
What it means
GroundOverlayOptions.position(LatLng, float width) throws IllegalStateException when the position was already specified via positionFromBounds(LatLngBounds). A ground overlay supports exactly one positioning strategy — an anchor point with explicit dimensions, or bounds-fitting — and calling both is contradictory. The builder detects the conflict by checking the internal bounds field.
Source
Thrown at play-services-maps/src/main/java/com/google/android/gms/maps/model/GroundOverlayOptions.java:291
* given image will remain fixed. The anchor will remain fixed to the position
* on the ground when transformations are applied (e.g., setDimensions,
* setBearing, etc.).
* @param width the width of the overlay (in meters). The height will be determined
* automatically based on the image proportions.
* @return this {@link GroundOverlayOptions} object with a new position set.
* @throws IllegalArgumentException if anchor is null
* @throws IllegalArgumentException if width is negative
* @throws IllegalStateException if the position was already set using
* {@link #positionFromBounds(LatLngBounds)}
*/
public GroundOverlayOptions position(LatLng location, float width)
throws IllegalArgumentException, IllegalStateException {
if (location == null)
throw new IllegalArgumentException("location must not be null");
if (width < 0)
throw new IllegalArgumentException("width must not be negative");
if (bounds != null)
throw new IllegalStateException("Position already set using positionFromBounds()");
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)View on GitHub (pinned to 157c9d86ac)
Solutions
- Pick one positioning method: remove the position(...) call if using positionFromBounds(...), or the reverse.
- When reusing options across overlays, create a fresh GroundOverlayOptions per overlay instead of mutating a shared builder.
- Track which positioning method was applied (a flag or separate builder paths) and call only one.
Example fix
// before
GroundOverlayOptions opts = new GroundOverlayOptions()
.positionFromBounds(bounds);
if (anchor != null) {
opts.position(anchor, 1000f); // IllegalStateException
}
// after
GroundOverlayOptions opts = new GroundOverlayOptions();
if (anchor != null) {
opts.position(anchor, 1000f);
} else {
opts.positionFromBounds(bounds);
} Defensive patterns
Strategy: validation
Validate before calling
if (usingBounds) { /* do not call position(...) */ } Type guard
boolean isPositionFree(GroundOverlayOptions o) { return !o.getBoundsSet(); } // track it yourself with a flag Try / catch
try {
options.position(anchor, width);
} catch (IllegalStateException e) {
// already positioned via positionFromBounds(); keep that strategy
} Prevention
- Choose one positioning strategy per overlay and enforce it in code structure.
- Create a fresh GroundOverlayOptions per overlay instead of reusing a shared builder.
- Build options in exclusive if/else branches.
When it happens
Trigger: Fluent chains that call positionFromBounds(...) earlier and then position(...) later (or vice versa) on the same GroundOverlayOptions, often when options are assembled conditionally from different code paths that each set a position.
Common situations: Reusing a single GroundOverlayOptions instance across multiple overlays where one path sets bounds and another sets position; refactoring code that switched positioning strategy without removing the old call; conditional configuration where both branches execute.
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
- Position already set using position()
- height must not be negative
- location must not be null
- width must not be negative
- transparency must be in range [0..1]
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/70197f87caa5e9c9.
Report an issue: GitHub.