microg/GmsCore · error · IllegalStateException

Must not be invoked on main thread

Error message

Must not be invoked on main thread

What it means

The unbounded Tasks.await(task) overload blocks the calling thread indefinitely, so it refuses to run on the Android main thread: it compares Looper.getMainLooper().getThread() to the current thread and throws IllegalStateException('Must not be invoked on main thread'). Blocking the main thread would freeze the UI and trigger ANRs.

Source

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

        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);
    }

    private static <TResult> TResult handleCompletedTask(Task<TResult> task) throws ExecutionException {
        if (task.isSuccessful()) {
            return task.getResult();
        }
        if (task.isCanceled()) {
            throw new CancellationException("Task is already canceled");
        }
        throw new ExecutionException(task.getException());
    }

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Move the await call to a background thread (worker thread, executor, or coroutine dispatch to IO)
  2. Use the listener-based APIs (addOnCompleteListener/addOnSuccessListener) instead of blocking await on the main thread
  3. Check Looper.myLooper() == Looper.getMainLooper() in your own wrapper and route to a background executor
  4. Use Tasks.await(task, timeout, unit) off-thread if you need a bounded wait

Example fix

// before // in onCreate() on main thread
User u = Tasks.await(getUserTask());
// after
executor.execute(() -> {
    try {
        User u = Tasks.await(getUserTask());
    } catch (ExecutionException | InterruptedException e) {
        // handle
    }
});
Defensive patterns

Strategy: validation

Validate before calling

if (Looper.myLooper() == Looper.getMainLooper()) {
    throw new IllegalStateException("await must run off the main thread");
}

Try / catch

try {
    T r = Tasks.await(task);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("main thread")) { /* re-dispatch to background executor */ }
} catch (ExecutionException | InterruptedException e) {
    // normal failure handling
}

Prevention

When it happens

Trigger: Calling Tasks.await(task) from an Activity/Fragment method, a UI click handler, or any code executing on the main looper.

Common situations: Quick demo code written in onCreate; calling await from a ViewModel method invoked on the main thread; forgetting that callbacks like onClick run on the main thread.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


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