{"record":{"id":"57fbd8df03cff2fb","repo":"microg/GmsCore","slug":"executor-must-not-be-null","errorCode":null,"errorMessage":"Executor must not be null","messagePattern":"Executor must not be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java","lineNumber":115,"sourceCode":"     * @deprecated Use {@link TaskCompletionSource} instead, which allows the caller to manage their own Executor.\n     */\n    @Deprecated\n    public static <TResult> Task<TResult> call(Callable<TResult> callable) {\n        return call(TaskExecutors.MAIN_THREAD, callable);\n    }\n\n    /**\n     * Returns a {@link Task} that will be completed with the result of the specified {@code Callable}.\n     * <p/>\n     * If a non-{@link Exception} throwable is thrown in the callable, the {@link Task} will be failed with a\n     * {@link RuntimeException} whose cause is the original throwable.\n     *\n     * @param executor the Executor to use to call the {@code Callable}\n     * @deprecated Use {@link TaskCompletionSource} instead, which allows the caller to manage their own Executor.\n     */\n    @Deprecated\n    public static <TResult> Task<TResult> call(Executor executor, Callable<TResult> callable) {\n        if (executor == null) throw new IllegalArgumentException(\"Executor must not be null\");\n        if (callable == null) throw new IllegalArgumentException(\"Callable must not be null\");\n        TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<>();\n        executor.execute(() -> {\n            try {\n                taskCompletionSource.setResult(callable.call());\n            } catch (Exception e) {\n                taskCompletionSource.trySetException(e);\n            } catch (Throwable t) {\n                taskCompletionSource.trySetException(new RuntimeException(t));\n            }\n        });\n        return taskCompletionSource.getTask();\n    }\n\n    /**\n     * Returns a canceled Task.\n     */\n    public static <TResult> Task<TResult> forCancelled() {","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java#L97-L133","documentation":"The deprecated Tasks.call(Executor, Callable) validates its arguments up front. A null Executor cannot schedule the Callable, so the method throws this IllegalArgumentException immediately instead of failing later inside executor.execute().","triggerScenarios":"Calling Tasks.call(null, callable), usually because the Executor came from a variable/config that is null (e.g. a field never initialized, an injected executor not provided, or doInBackground-style code passing null to use 'default' behavior).","commonSituations":"Migrating code from Tasks.call(Callable) to the executor variant and passing null hoping for a default executor; dependency-injection graph missing an Executor binding; custom Executor created conditionally (e.g. after a permission/setup step) but call() runs earlier.","solutions":["Pass a real Executor, e.g. Executors.newSingleThreadExecutor(), or TaskExecutors/ContextCompat.getMainExecutor(context)","Keep using the no-executor overload Tasks.call(Callable) only if you intend the deprecated default behavior — better: migrate to TaskCompletionSource as the Javadoc recommends","Audit where the Executor value originates and ensure it is initialized before Tasks.call is invoked"],"exampleFix":"// before\nTask<String> task = Tasks.call(null, () -> loadData()); // throws\n// after\nExecutor executor = Executors.newSingleThreadExecutor();\nTask<String> task = Tasks.call(executor, () -> loadData());\n// or preferred modern form:\nTaskCompletionSource<String> tcs = new TaskCompletionSource<>();\nexecutor.execute(() -> { try { tcs.setResult(loadData()); } catch (Exception e) { tcs.setException(e); } });","handlingStrategy":"validation","validationCode":"if (executor == null) {\n    executor = Executors.newSingleThreadExecutor();\n}","typeGuard":"static boolean isRunnableExecutor(Executor e) {\n    return e != null;\n}","tryCatchPattern":"try {\n    Task<T> t = Tasks.call(executor, callable);\n} catch (IllegalArgumentException e) {\n    // fall back to a default executor\n    Task<T> t = Tasks.call(Executors.newSingleThreadExecutor(), callable);\n}","preventionTips":["Standardize on one Executor provider (DI binding or utility) so it is never null","Prefer Tasks.call(Callable) or TaskCompletionSource over the deprecated executor overload","Initialize executors in Application/Component creation, not lazily at call sites"],"tags":["android","null-check","executor","deprecated-api"],"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"}