microg/GmsCore · error · IllegalArgumentException
Timeout must be positive
Error message
Timeout must be positive
What it means
Tasks.await(task, timeout, unit) requires a strictly positive timeout and throws IllegalArgumentException for timeout <= 0. A non-positive timeout cannot ever elapse usefully, so the call is rejected before waiting.
Source
Thrown at play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java:50
import java.util.concurrent.atomic.AtomicReference;
/**
* {@link Task} utility methods.
*/
@PublicApi
public final class Tasks {
/**
* Blocks until the specified Task is complete.
*
* @return the Task's result
* @throws ExecutionException if the Task fails
* @throws InterruptedException if an interrupt occurs while waiting for the Task to complete
* @throws TimeoutException if the specified timeout is reached before the Task completes
*/
public static <TResult> TResult await(Task<TResult> task, long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {
if (task == null) throw new IllegalArgumentException("Task must not be null");
if (timeout <= 0) throw new IllegalArgumentException("Timeout must be positive");
if (unit == null) throw new IllegalArgumentException("TimeUnit must not be null");
if (task.isComplete()) return handleCompletedTask(task);
CountDownLatch latch = new CountDownLatch(1);
task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());
if (latch.await(timeout, unit)) {
return handleCompletedTask(task);
}
throw new TimeoutException("Timed out waiting for Task");
}
/**
* Blocks until the specified Task is complete.
*
* @return the Task's result
* @throws ExecutionException if the Task fails
* @throws InterruptedException if an interrupt occurs while waiting for the Task to complete
*/
public static <TResult> TResult await(Task<TResult> task) throws ExecutionException, InterruptedException {View on GitHub (pinned to 157c9d86ac)
Solutions
- Pass a positive timeout value, e.g. Tasks.await(task, 5, TimeUnit.SECONDS)
- If waiting indefinitely, use the no-timeout Tasks.await(task) overload (off the main thread)
- Clamp computed remaining time: Math.max(1, deadline - now) and skip await when already expired
- Audit unit conversions so the numeric value matches the TimeUnit
Example fix
// before
long remaining = deadline - System.currentTimeMillis(); // can be <= 0
T r = Tasks.await(task, remaining, TimeUnit.MILLISECONDS);
// after
long remaining = deadline - System.currentTimeMillis();
if (remaining > 0) {
T r = Tasks.await(task, remaining, TimeUnit.MILLISECONDS);
} else {
throw new TimeoutException();
} Defensive patterns
Strategy: validation
Validate before calling
if (timeout <= 0) throw new IllegalArgumentException("timeout must be > 0, got " + timeout); Try / catch
try {
T r = Tasks.await(task, timeout, TimeUnit.SECONDS);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Timeout must be positive")) { /* fix timeout computation */ }
} Prevention
- Validate computed remaining-time values before awaiting
- Use named constants (e.g. DEFAULT_TIMEOUT_SECONDS = 30) instead of bare 0/negatives
- Keep timeout value and TimeUnit together in one config object
- When deadlines may already be expired, throw TimeoutException yourself instead of calling await
When it happens
Trigger: Calling Tasks.await(task, 0, unit) or Tasks.await(task, -1, unit) — hardcoding 0, computing a deadline that already passed (now - deadline), or misunitizing (thinking the value is milliseconds when it is seconds).
Common situations: Computed remaining-time expressions that went negative; refactors that changed timeout units; tests passing 0 to expect immediate completion.
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Task must not be null
- TimeUnit must not be null
- Timed out waiting for Task
- Must not be invoked on main thread
- deleteAll was set to true but keys were also provided
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/d15c83ae7e86843d.
Report an issue: GitHub.