microg/GmsCore · error · IllegalArgumentException

maxUpdateDelayMillis must be greater than or equal to 0

Error message

maxUpdateDelayMillis must be greater than or equal to 0

What it means

setMaxUpdateDelayMillis validates that the batching delay is non-negative. This value controls how long a location update may be held back to batch deliveries; a negative delay has no meaning, so the builder throws IllegalArgumentException immediately.

Source

Thrown at play-services-location/src/main/java/com/google/android/gms/location/LocationRequest.java:750

         * as high as is reasonable to allow for additional power savings. When the {@link LocationRequest} is built, the maximum
         * update delay will be set to the max of the provided maximum update delay and the interval. This normalizes requests
         * without batching to have the maximum update delay equal to the interval.
         * <p>
         * For example, if a request is made with a 2s interval and a 10s maximum update delay, this implies that the device may
         * choose to deliver batches of 5 locations every 10s (where each location in a batch represents a point in time ~2s after
         * the previous).
         * <p>
         * Support for batching may vary by device hardware, so simply allowing batching via this parameter does not imply a client
         * will receive batched results on all devices.
         * <p>
         * {@link FusedLocationProviderClient#flushLocations()} may be used to flush locations that have been batched, but not
         * delivered yet.
         * <p>
         * The default value is 0.
         */
        @NonNull
        public Builder setMaxUpdateDelayMillis(long maxUpdateDelayMillis) {
            if (maxUpdateDelayMillis < 0) throw new IllegalArgumentException("maxUpdateDelayMillis must be greater than or equal to 0");
            this.maxUpdateDelayMillis = maxUpdateDelayMillis;
            return this;
        }

        /**
         * Sets the maximum number of updates delivered to this request. A location request will not receive any locations after the
         * maximum number of updates has been reached, and will be removed shortly thereafter. A value of {@link Integer#MAX_VALUE}
         * implies an unlimited number of updates.
         * <p>
         * The default value is {@link Integer#MAX_VALUE}.
         */
        @NonNull
        public Builder setMaxUpdates(int maxUpdates) {
            if (maxUpdates <= 0) throw new IllegalArgumentException("maxUpdates must be greater than 0");
            this.maxUpdates = maxUpdates;
            return this;
        }

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Clamp the value before the call: builder.setMaxUpdateDelayMillis(Math.max(0, delayMillis)).
  2. Validate config/user-supplied delays at the boundary so negatives never reach the builder.
  3. Confirm argument order in any wrapper method that forwards parameters to setMaxUpdateDelayMillis.

Example fix

// before
long delay = maxDelay - extra; // may be negative
builder.setMaxUpdateDelayMillis(delay);
// after
long delay = Math.max(0, maxDelay - extra);
builder.setMaxUpdateDelayMillis(delay);
Defensive patterns

Strategy: validation

Validate before calling

public static boolean isValidMaxUpdateDelay(long delayMillis) {
    return delayMillis >= 0;
}
long safeDelay = Math.max(0, requestedDelay);

Type guard

static boolean isNonNegative(long v) { return v >= 0; }

Try / catch

try {
    return builder.setMaxUpdateDelayMillis(delay);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("maxUpdateDelayMillis")) throw e;
    return builder.setMaxUpdateDelayMillis(0); // disable batching on bad input
}

Prevention

When it happens

Trigger: Calling builder.setMaxUpdateDelayMillis(-1) or any negative long, often from a computed value like (budget - overrun) or a mis-signed config field.

Common situations: Dynamically shrinking a batching delay faster than the current delay value; server-driven config containing negative delays; parameter-order mix-ups when a helper wraps the builder and forwards arguments in the wrong sequence.

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/67dbd978e638532f. Report an issue: GitHub.