{"record":{"id":"5054ea9a4c1aedf6","repo":"microg/GmsCore","slug":"null-tasks-are-not-accepted","errorCode":null,"errorMessage":"null tasks are not accepted","messagePattern":"null tasks are not accepted","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java","lineNumber":171,"sourceCode":"        task.setResult(result);\n        return task;\n    }\n\n    /**\n     * Returns a Task that completes successfully when all of the specified Tasks complete\n     * successfully. Does not accept nulls.\n     * <p/>\n     * The returned Task would fail if any of the provided Tasks fail. The returned Task would be set to canceled if\n     * any of the provided Tasks is canceled and no failure is detected.\n     *\n     * @throws NullPointerException if any of the provided Tasks are null\n     */\n    public static Task<Void> whenAll(Collection<? extends Task<?>> tasks) {\n        if (tasks == null || tasks.isEmpty()) {\n            return forResult(null);\n        }\n        for (Task<?> task : tasks) {\n            if (task == null) throw new NullPointerException(\"null tasks are not accepted\");\n        }\n        TaskImpl<Void> allTask = new TaskImpl<>();\n        AtomicInteger finishedTasks = new AtomicInteger(0);\n        AtomicInteger failedTasks = new AtomicInteger(0);\n        AtomicReference<Exception> exceptionReference = new AtomicReference<>(null);\n        AtomicBoolean isCancelled = new AtomicBoolean(false);\n        for (Task<?> task : tasks) {\n            task.addOnCompleteListener(Runnable::run, completedTask -> {\n                if (!completedTask.isSuccessful()) {\n                    if (completedTask.isCanceled()) {\n                        isCancelled.set(true);\n                    } else {\n                        exceptionReference.set(completedTask.getException());\n                        failedTasks.incrementAndGet();\n                    }\n                }\n                if (finishedTasks.incrementAndGet() != tasks.size()) return;\n                Exception exception = exceptionReference.get();","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java#L153-L189","documentation":"Tasks.whenAll(Collection) collects a group of Tasks into one Task that completes when all inputs finish. Null and empty collections are tolerated (producing an already-complete task), but any individual null element inside the collection is rejected with this NullPointerException, since a null Task can never complete and would deadlock the aggregate.","triggerScenarios":"Calling Tasks.whenAll(list) where the list contains null entries — typically built by conditionally adding results of Task-returning calls that returned null (e.g. list.add(api.getTask()) with getTask() null), or a fixed-size array with unfilled slots.","commonSituations":"Building a batch of Firestore/Firebase writes where one request failed to produce a Task; parallelizing uploads with a loop that adds null when a file is missing; passing an ArrayList preallocated with nulls.","solutions":["Filter nulls before aggregating: tasks.removeIf(Objects::isNull) or stream().filter(Objects::nonNull)","Fix the producer so every API call returns a valid Task (failed work should be a failed Task, not null)","Alternatively replace with Tasks.whenAllSuccess/whenAllComplete over a defensively validated collection"],"exampleFix":"// before\nList<Task<Void>> tasks = new ArrayList<>();\nfor (String id : ids) tasks.add(upload(id)); // upload() can return null\nTasks.whenAll(tasks); // NPE if any element is null\n// after\nList<Task<Void>> tasks = new ArrayList<>();\nfor (String id : ids) {\n    Task<Void> t = upload(id);\n    if (t != null) tasks.add(t);\n}\nTasks.whenAll(tasks);","handlingStrategy":"validation","validationCode":"List<Task<?>> safe = new ArrayList<>();\nfor (Task<?> t : tasks) {\n    if (t != null) safe.add(t);\n}\n// then: Tasks.whenAll(safe);","typeGuard":"static List<Task<?>> nonNullTasks(Collection<Task<?>> in) {\n    return in.stream().filter(Objects::nonNull).collect(Collectors.toList());\n}","tryCatchPattern":"try {\n    Tasks.whenAll(tasks).await();\n} catch (NullPointerException e) {\n    // a null element slipped in - filter and retry\n} catch (ExecutionException | InterruptedException e) {\n    // per-task failures / interruption\n}","preventionTips":["Never add Task-producing call results without checking for null","Make producers return failed Tasks (setException) rather than null","Filter with Objects::isNull before aggregation","Avoid preallocated ArrayLists with null slots"],"tags":["android","null-check","whenall","batch"],"backgroundTag":"null-argument","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"}