{"record":{"id":"67dbd978e638532f","repo":"microg/GmsCore","slug":"maxupdatedelaymillis-must-be-greater-than-or-equal","errorCode":null,"errorMessage":"maxUpdateDelayMillis must be greater than or equal to 0","messagePattern":"maxUpdateDelayMillis must be greater than or equal to 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"play-services-location/src/main/java/com/google/android/gms/location/LocationRequest.java","lineNumber":750,"sourceCode":"         * as high as is reasonable to allow for additional power savings. When the {@link LocationRequest} is built, the maximum\n         * update delay will be set to the max of the provided maximum update delay and the interval. This normalizes requests\n         * without batching to have the maximum update delay equal to the interval.\n         * <p>\n         * For example, if a request is made with a 2s interval and a 10s maximum update delay, this implies that the device may\n         * choose to deliver batches of 5 locations every 10s (where each location in a batch represents a point in time ~2s after\n         * the previous).\n         * <p>\n         * Support for batching may vary by device hardware, so simply allowing batching via this parameter does not imply a client\n         * will receive batched results on all devices.\n         * <p>\n         * {@link FusedLocationProviderClient#flushLocations()} may be used to flush locations that have been batched, but not\n         * delivered yet.\n         * <p>\n         * The default value is 0.\n         */\n        @NonNull\n        public Builder setMaxUpdateDelayMillis(long maxUpdateDelayMillis) {\n            if (maxUpdateDelayMillis < 0) throw new IllegalArgumentException(\"maxUpdateDelayMillis must be greater than or equal to 0\");\n            this.maxUpdateDelayMillis = maxUpdateDelayMillis;\n            return this;\n        }\n\n        /**\n         * Sets the maximum number of updates delivered to this request. A location request will not receive any locations after the\n         * maximum number of updates has been reached, and will be removed shortly thereafter. A value of {@link Integer#MAX_VALUE}\n         * implies an unlimited number of updates.\n         * <p>\n         * The default value is {@link Integer#MAX_VALUE}.\n         */\n        @NonNull\n        public Builder setMaxUpdates(int maxUpdates) {\n            if (maxUpdates <= 0) throw new IllegalArgumentException(\"maxUpdates must be greater than 0\");\n            this.maxUpdates = maxUpdates;\n            return this;\n        }\n","sourceCodeStart":732,"sourceCodeEnd":768,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-location/src/main/java/com/google/android/gms/location/LocationRequest.java#L732-L768","documentation":"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.","triggerScenarios":"Calling builder.setMaxUpdateDelayMillis(-1) or any negative long, often from a computed value like (budget - overrun) or a mis-signed config field.","commonSituations":"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.","solutions":["Clamp the value before the call: builder.setMaxUpdateDelayMillis(Math.max(0, delayMillis)).","Validate config/user-supplied delays at the boundary so negatives never reach the builder.","Confirm argument order in any wrapper method that forwards parameters to setMaxUpdateDelayMillis."],"exampleFix":"// before\nlong delay = maxDelay - extra; // may be negative\nbuilder.setMaxUpdateDelayMillis(delay);\n// after\nlong delay = Math.max(0, maxDelay - extra);\nbuilder.setMaxUpdateDelayMillis(delay);","handlingStrategy":"validation","validationCode":"public static boolean isValidMaxUpdateDelay(long delayMillis) {\n    return delayMillis >= 0;\n}\nlong safeDelay = Math.max(0, requestedDelay);","typeGuard":"static boolean isNonNegative(long v) { return v >= 0; }","tryCatchPattern":"try {\n    return builder.setMaxUpdateDelayMillis(delay);\n} catch (IllegalArgumentException e) {\n    if (!e.getMessage().contains(\"maxUpdateDelayMillis\")) throw e;\n    return builder.setMaxUpdateDelayMillis(0); // disable batching on bad input\n}","preventionTips":["Clamp dynamic batching delays: Math.max(0, budget - overrun).","Validate server/config-driven delay values at deserialization time.","In wrapper APIs, assert argument order before forwarding longs to the builder."],"tags":["android","location","illegal-argument","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}