{"record":{"id":"d15c83ae7e86843d","repo":"microg/GmsCore","slug":"timeout-must-be-positive","errorCode":null,"errorMessage":"Timeout must be positive","messagePattern":"Timeout must be positive","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java","lineNumber":50,"sourceCode":"import java.util.concurrent.atomic.AtomicReference;\n\n/**\n * {@link Task} utility methods.\n */\n@PublicApi\npublic final class Tasks {\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     * @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 {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java#L32-L68","documentation":"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.","triggerScenarios":"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).","commonSituations":"Computed remaining-time expressions that went negative; refactors that changed timeout units; tests passing 0 to expect immediate completion.","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"],"exampleFix":"// before\nlong remaining = deadline - System.currentTimeMillis(); // can be <= 0\nT r = Tasks.await(task, remaining, TimeUnit.MILLISECONDS);\n// after\nlong remaining = deadline - System.currentTimeMillis();\nif (remaining > 0) {\n    T r = Tasks.await(task, remaining, TimeUnit.MILLISECONDS);\n} else {\n    throw new TimeoutException();\n}","handlingStrategy":"validation","validationCode":"if (timeout <= 0) throw new IllegalArgumentException(\"timeout must be > 0, got \" + timeout);","typeGuard":null,"tryCatchPattern":"try {\n    T r = Tasks.await(task, timeout, TimeUnit.SECONDS);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Timeout must be positive\")) { /* fix timeout computation */ }\n}","preventionTips":["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"],"tags":["tasks","illegal-argument","timeout","await"],"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-14T00:17:10.932Z"}