microg/GmsCore · error · TimeoutException

Timed out waiting for Task

Error message

Timed out waiting for Task

What it means

When the task does not complete within the given timeout, Tasks.await(task, timeout, unit) stops waiting on the latch and throws TimeoutException('Timed out waiting for Task'). This is a checked exception signaling the operation took too long, not that it failed.

Source

Thrown at play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java:58

    /**
     * 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 {
        if (Looper.getMainLooper().getThread() == Thread.currentThread())
            throw new IllegalStateException("Must not be invoked on main thread");
        if (task == null) throw new IllegalArgumentException("Task must not be null");
        if (task.isComplete()) return handleCompletedTask(task);
        CountDownLatch latch = new CountDownLatch(1);
        task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());
        latch.await();
        return handleCompletedTask(task);

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Increase the timeout to a realistic bound for the operation
  2. Use the unbounded Tasks.await(task) overload on a background thread when there is no deadline
  3. Cancel/abandon the work gracefully and retry with backoff on TimeoutException
  4. Verify the task's completion listener can actually run (executor alive, process not blocked) so the latch counts down

Example fix

// before
T r = Tasks.await(task, 500, TimeUnit.MILLISECONDS); // too short
// after
try {
    T r = Tasks.await(task, 30, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    // retry or surface timeout to caller
}
Defensive patterns

Strategy: try-catch

Validate before calling

// estimate: skip await when deadline already passed
if (timeoutMs <= 0) throw new TimeoutException("deadline already passed");

Try / catch

try {
    T r = Tasks.await(task, timeout, unit);
} catch (TimeoutException e) {
    // cancel UI spinner, retry with backoff, or surface timeout
} catch (ExecutionException e) {
    // task itself failed
}

Prevention

When it happens

Trigger: Calling the timed-overload with a timeout shorter than the task's actual duration: slow network calls, large payloads, stalled backend, or a task whose listener was registered on a dead executor so the latch never counts down.

Common situations: Mobile networks with high latency; too-aggressive timeout constants in config; background work exceeding UI-driven deadlines; debugger breakpoints pausing the completing thread.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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