{"record":{"id":"56f11663206f99ce","repo":"alibaba/ARouter","slug":"timeunit-must-not-be-null","errorCode":null,"errorMessage":"TimeUnit must not be null.","messagePattern":"TimeUnit must not be null\\.","errorType":"exception","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"arouter-api/src/main/java/com/alibaba/android/arouter/core/InterceptorInitState.java","lineNumber":75,"sourceCode":"            lock.notifyAll();\n        }\n    }\n\n    void fail(Throwable cause) {\n        if (cause == null) {\n            throw new IllegalArgumentException(\"Interceptor initialization failure must have a cause.\");\n        }\n\n        synchronized (lock) {\n            status = Status.FAILED;\n            failure = cause;\n            lock.notifyAll();\n        }\n    }\n\n    Result await(long timeout, TimeUnit unit) throws InterruptedException {\n        if (unit == null) {\n            throw new NullPointerException(\"TimeUnit must not be null.\");\n        }\n\n        long timeoutNanos = unit.toNanos(timeout);\n        long startNanos = System.nanoTime();\n\n        synchronized (lock) {\n            while (status != Status.SUCCEEDED && status != Status.FAILED) {\n                long elapsedNanos = System.nanoTime() - startNanos;\n                long remainingNanos = timeoutNanos - elapsedNanos;\n                if (remainingNanos <= 0) {\n                    return new Result(Outcome.TIMEOUT, null);\n                }\n\n                TimeUnit.NANOSECONDS.timedWait(lock, remainingNanos);\n            }\n\n            if (status == Status.FAILED) {\n                return new Result(Outcome.FAILURE, failure);","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/alibaba/ARouter/blob/84f451d244e3fb1d0e37801de1b9ee2af2f81d68/arouter-api/src/main/java/com/alibaba/android/arouter/core/InterceptorInitState.java#L57-L93","documentation":"InterceptorInitState.await(timeout, unit) converts the timeout to nanoseconds using the TimeUnit, so a null unit cannot be handled. It throws NullPointerException immediately to fail fast instead of dying inside unit.toNanos().","triggerScenarios":"Calling await(timeout, null) — usually because a TimeUnit constant was deleted, refactored to a nullable parameter, or a caller passed a unit variable that was never initialized.","commonSituations":"Configurable timeout code where the TimeUnit is read from config/defaults and a default was omitted; tests passing null to shortcut the wait.","solutions":["Pass an explicit TimeUnit, e.g. TimeUnit.SECONDS, at every await() call site","If the unit is configurable, default it before calling await","Prefer the MILLIS/SECONDS constant that matches the timeout magnitude to avoid silent unit bugs"],"exampleFix":"// before\nResult r = initState.await(timeout, null);\n// after\nResult r = initState.await(timeout, TimeUnit.SECONDS);","handlingStrategy":"validation","validationCode":"Objects.requireNonNull(unit, \"TimeUnit must not be null\");\nResult r = initState.await(timeout, unit);","typeGuard":null,"tryCatchPattern":"try {\n    return initState.await(timeout, TimeUnit.SECONDS);\n} catch (InterruptedException e) {\n    Thread.currentThread().interrupt();\n    return Result.INTERRUPTED;\n}","preventionTips":["Always pass an explicit TimeUnit constant","Default configurable units before the await call","Prefer SECONDS/MILLIS constants over dynamic unit lookup"],"tags":["arouter","interceptor","null-argument","timeunit"],"backgroundTag":"null-argument","analyzedSha":"84f451d244e3fb1d0e37801de1b9ee2af2f81d68","analyzedAt":"2026-09-06T13:30:41.084Z","contentChangedAt":"2026-09-06T13:30:41.084Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}