{"record":{"id":"0341d277e47706c5","repo":"microg/GmsCore","slug":"timed-out-waiting-for-task","errorCode":null,"errorMessage":"Timed out waiting for Task","messagePattern":"Timed out waiting for Task","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java","lineNumber":58,"sourceCode":"    /**\n     * Blocks until the specified Task is complete.\n     *\n     * @return the Task's result\n     * @throws ExecutionException   if the Task fails\n     * @throws InterruptedException if an interrupt occurs while waiting for the Task to complete\n     * @throws TimeoutException     if the specified timeout is reached before the Task completes\n     */\n    public static <TResult> TResult await(Task<TResult> task, long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {\n        if (task == null) throw new IllegalArgumentException(\"Task must not be null\");\n        if (timeout <= 0) throw new IllegalArgumentException(\"Timeout must be positive\");\n        if (unit == null) throw new IllegalArgumentException(\"TimeUnit must not be null\");\n        if (task.isComplete()) return handleCompletedTask(task);\n        CountDownLatch latch = new CountDownLatch(1);\n        task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());\n        if (latch.await(timeout, unit)) {\n            return handleCompletedTask(task);\n        }\n        throw new TimeoutException(\"Timed out waiting for Task\");\n    }\n\n    /**\n     * Blocks until the specified Task is complete.\n     *\n     * @return the Task's result\n     * @throws ExecutionException   if the Task fails\n     * @throws InterruptedException if an interrupt occurs while waiting for the Task to complete\n     */\n    public static <TResult> TResult await(Task<TResult> task) throws ExecutionException, InterruptedException {\n        if (Looper.getMainLooper().getThread() == Thread.currentThread())\n            throw new IllegalStateException(\"Must not be invoked on main thread\");\n        if (task == null) throw new IllegalArgumentException(\"Task must not be null\");\n        if (task.isComplete()) return handleCompletedTask(task);\n        CountDownLatch latch = new CountDownLatch(1);\n        task.addOnCompleteListener(Runnable::run, completedTask -> latch.countDown());\n        latch.await();\n        return handleCompletedTask(task);","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java#L40-L76","documentation":"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.","triggerScenarios":"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.","commonSituations":"Mobile networks with high latency; too-aggressive timeout constants in config; background work exceeding UI-driven deadlines; debugger breakpoints pausing the completing thread.","solutions":["Increase the timeout to a realistic bound for the operation","Use the unbounded Tasks.await(task) overload on a background thread when there is no deadline","Cancel/abandon the work gracefully and retry with backoff on TimeoutException","Verify the task's completion listener can actually run (executor alive, process not blocked) so the latch counts down"],"exampleFix":"// before\nT r = Tasks.await(task, 500, TimeUnit.MILLISECONDS); // too short\n// after\ntry {\n    T r = Tasks.await(task, 30, TimeUnit.SECONDS);\n} catch (TimeoutException e) {\n    // retry or surface timeout to caller\n}","handlingStrategy":"try-catch","validationCode":"// estimate: skip await when deadline already passed\nif (timeoutMs <= 0) throw new TimeoutException(\"deadline already passed\");","typeGuard":null,"tryCatchPattern":"try {\n    T r = Tasks.await(task, timeout, unit);\n} catch (TimeoutException e) {\n    // cancel UI spinner, retry with backoff, or surface timeout\n} catch (ExecutionException e) {\n    // task itself failed\n}","preventionTips":["Size timeouts from measured p95 latencies, not guesses","Catch TimeoutException separately from ExecutionException to distinguish slow vs failed","Add retry-with-backoff around transient operations","Use bounded waits plus explicit cancellation instead of unbounded blocking"],"tags":["tasks","timeout","await","latch"],"backgroundTag":"request-timeout","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"}