microg/GmsCore · error · IllegalArgumentException
Callable must not be null
Error message
Callable must not be null
What it means
The deprecated Tasks.call(Executor, Callable) requires a non-null Callable whose body produces the task result. A null Callable has nothing to run on the executor, so the method throws this IllegalArgumentException immediately.
Source
Thrown at play-services-tasks/src/main/java/com/google/android/gms/tasks/Tasks.java:116
*/
@Deprecated
public static <TResult> Task<TResult> call(Callable<TResult> callable) {
return call(TaskExecutors.MAIN_THREAD, callable);
}
/**
* Returns a {@link Task} that will be completed with the result of the specified {@code Callable}.
* <p/>
* If a non-{@link Exception} throwable is thrown in the callable, the {@link Task} will be failed with a
* {@link RuntimeException} whose cause is the original throwable.
*
* @param executor the Executor to use to call the {@code Callable}
* @deprecated Use {@link TaskCompletionSource} instead, which allows the caller to manage their own Executor.
*/
@Deprecated
public static <TResult> Task<TResult> call(Executor executor, Callable<TResult> callable) {
if (executor == null) throw new IllegalArgumentException("Executor must not be null");
if (callable == null) throw new IllegalArgumentException("Callable must not be null");
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<>();
executor.execute(() -> {
try {
taskCompletionSource.setResult(callable.call());
} catch (Exception e) {
taskCompletionSource.trySetException(e);
} catch (Throwable t) {
taskCompletionSource.trySetException(new RuntimeException(t));
}
});
return taskCompletionSource.getTask();
}
/**
* Returns a canceled Task.
*/
public static <TResult> Task<TResult> forCancelled() {
TaskImpl<TResult> task = new TaskImpl<>();View on GitHub (pinned to 157c9d86ac)
Solutions
- Pass a real Callable implementation/lambda; if the work is optional, guard the call site instead of passing null
- Return an already-completed Task via Tasks.forResult(defaultValue) when there is no work to run
- Migrate to TaskCompletionSource (per deprecation notice) and only start work when the callable exists
Example fix
// before
Task<Integer> task = Tasks.call(executor, getCallable()); // getCallable() may return null
// after
Callable<Integer> c = getCallable();
Task<Integer> task = (c != null)
? Tasks.call(executor, c)
: Tasks.forResult(0); // or skip the call entirely Defensive patterns
Strategy: validation
Validate before calling
if (callable == null) {
return Tasks.forResult(defaultValue); // nothing to run
} Type guard
static <T> boolean hasWork(Callable<T> c) {
return c != null;
} Try / catch
try {
Task<T> t = Tasks.call(executor, callable);
} catch (IllegalArgumentException e) {
// skip or provide default result
Task<T> t = Tasks.forResult(null);
} Prevention
- Guard optional computations at the call site instead of passing null Callables
- Return completed tasks (Tasks.forResult) when there is no work
- Migrate to TaskCompletionSource to make 'start work' explicit and null-impossible
When it happens
Trigger: Calling Tasks.call(executor, null), often from a generic helper that forwards a supplier/callable which is null (uninitialized lambda field, optional computation skipped), or reflective/dynamic code that failed to build the Callable.
Common situations: Kotlin/Java interop where a Kotlin lambda coerced to Callable? arrives as null; helper methods like runIfConfigured(executor, maybeCallable) invoked when the computation is absent; refactors that removed the work but left the call site.
Related errors
- Executor must not be null
- Conflicting data sources found
- durationMillis must be greater than 0
- illegal fastest interval:
- intervalMillis must be greater than or equal to 0
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/c25542eeab9f2f9e.
Report an issue: GitHub.