{"record":{"id":"b82739bd5bddb9a5","repo":"ReactiveX/RxAndroid","slug":"scheduler-null","errorCode":null,"errorMessage":"scheduler == null","messagePattern":"scheduler == null","errorType":"exception","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"rxandroid/src/main/java/io/reactivex/rxjava3/android/plugins/RxAndroidPlugins.java","lineNumber":35,"sourceCode":"import io.reactivex.rxjava3.core.Scheduler;\nimport io.reactivex.rxjava3.exceptions.Exceptions;\nimport io.reactivex.rxjava3.functions.Function;\n\n/**\n * Utility class to inject handlers to certain standard RxAndroid operations.\n */\npublic final class RxAndroidPlugins {\n\n    private static volatile Function<Callable<Scheduler>, Scheduler> onInitMainThreadHandler;\n    private static volatile Function<Scheduler, Scheduler> onMainThreadHandler;\n\n    public static void setInitMainThreadSchedulerHandler(Function<Callable<Scheduler>, Scheduler> handler) {\n        onInitMainThreadHandler = handler;\n    }\n\n    public static Scheduler initMainThreadScheduler(Callable<Scheduler> scheduler) {\n        if (scheduler == null) {\n            throw new NullPointerException(\"scheduler == null\");\n        }\n        Function<Callable<Scheduler>, Scheduler> f = onInitMainThreadHandler;\n        if (f == null) {\n            return callRequireNonNull(scheduler);\n        }\n        return applyRequireNonNull(f, scheduler);\n    }\n\n    public static void setMainThreadSchedulerHandler(Function<Scheduler, Scheduler> handler) {\n        onMainThreadHandler = handler;\n    }\n\n    public static Scheduler onMainThreadScheduler(Scheduler scheduler) {\n        if (scheduler == null) {\n            throw new NullPointerException(\"scheduler == null\");\n        }\n        Function<Scheduler, Scheduler> f = onMainThreadHandler;\n        if (f == null) {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/ReactiveX/RxAndroid/blob/afaea280461456b30e6ea608428517476ddb8b39/rxandroid/src/main/java/io/reactivex/rxjava3/android/plugins/RxAndroidPlugins.java#L17-L53","documentation":"RxAndroidPlugins.initMainThreadScheduler(Callable<Scheduler>) throws this NullPointerException when the Callable argument itself is null. The method is the plugin entry point that AndroidSchedulers.main() uses to resolve the main-thread scheduler, and it refuses null input because there would be no way to construct a Scheduler. In normal library usage the Callable is an internal constant, so this NPE almost always means application or test code called the plugins API directly with null.","triggerScenarios":"Calling RxAndroidPlugins.initMainThreadScheduler(null) directly; a helper that wraps scheduler setup and passes a nullable variable that happened to be null; mocking frameworks returning null for the Callable in tests; reflective or copy-pasted initialization code that drops the argument.","commonSituations":"Test bootstrap code that intends to override the main scheduler but passes null instead of a Callable (e.g. RxAndroidPlugins.initMainThreadScheduler(null) instead of setInitMainThreadSchedulerHandler(callable -> Schedulers.trampoline())); Kotlin code where a Scheduler? or Callable<Scheduler>? leaks into the call; partial mocks in unit tests whose default stubbing returns null.","solutions":["Pass a real Callable: RxAndroidPlugins.initMainThreadScheduler(() -> Schedulers.trampoline()) — if your goal was overriding the scheduler, prefer RxAndroidPlugins.setInitMainThreadSchedulerHandler(callable -> Schedulers.trampoline()) instead.","Add a null check in your setup helper before calling the API and fail with a descriptive message.","In Kotlin, make the parameter non-null (Callable<Scheduler> instead of Callable<Scheduler>?) so the compiler rejects the call.","Fix mock stubbing: when(mockCallable.call()).thenReturn(scheduler), never thenReturn(null)."],"exampleFix":"// before\nRxAndroidPlugins.initMainThreadScheduler(null); // NPE: scheduler == null\n\n// after\nRxAndroidPlugins.setInitMainThreadSchedulerHandler(callable -> Schedulers.trampoline());","handlingStrategy":"validation","validationCode":"if (callable == null) {\n    throw new IllegalArgumentException(\"scheduler callable required\");\n}\nRxAndroidPlugins.initMainThreadScheduler(callable);","typeGuard":"public static boolean isUsableSchedulerCallable(Callable<Scheduler> c) {\n    if (c == null) return false;\n    try { return c.call() != null; } catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n    RxAndroidPlugins.initMainThreadScheduler(callable);\n} catch (NullPointerException e) {\n    if (\"scheduler == null\".equals(e.getMessage())) {\n        throw new IllegalStateException(\"Scheduler bootstrap misconfigured: callable missing\", e);\n    }\n    throw e;\n}","preventionTips":["Prefer the handler API (setInitMainThreadSchedulerHandler) for overrides; never pass a bare null to plugin methods.","In Kotlin, type scheduler inputs as non-null so the compiler rejects null at the call site.","Centralize all RxAndroidPlugins configuration in one bootstrap class instead of scattering direct plugin calls."],"tags":["rxandroid","rxjava","null-pointer","plugins","configuration"],"backgroundTag":null,"analyzedSha":"afaea280461456b30e6ea608428517476ddb8b39","analyzedAt":"2026-08-14T12:58:42.270Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}