{"record":{"id":"fdafc54794cb554b","repo":"walkor/workerman","slug":"timeinterval-can-not-less-than-0","errorCode":null,"errorMessage":"$timeInterval can not less than 0","messagePattern":"\\$timeInterval can not less than 0","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Timer.php","lineNumber":144,"sourceCode":"        if (!self::$event) {\n            pcntl_alarm(1);\n            self::tick();\n        }\n    }\n\n    /**\n     * Add a timer.\n     *\n     * @param float $timeInterval\n     * @param callable $func\n     * @param null|array $args\n     * @param bool $persistent\n     * @return int\n     */\n    public static function add(float $timeInterval, callable $func, ?array $args = [], bool $persistent = true): int\n    {\n        if ($timeInterval < 0) {\n            throw new RuntimeException('$timeInterval can not less than 0');\n        }\n\n        if ($args === null) {\n            $args = [];\n        }\n\n        if (self::$event) {\n            return $persistent ? self::$event->repeat($timeInterval, $func, $args) : self::$event->delay($timeInterval, $func, $args);\n        }\n\n        // If not workerman runtime just return.\n        if (!Worker::getAllWorkers()) {\n            throw new RuntimeException('Timer can only be used in workerman running environment');\n        }\n\n        if (empty(self::$tasks)) {\n            pcntl_alarm(1);\n        }","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/walkor/workerman/blob/1391112a61d23020e11e7b89f17050f6cfaea431/src/Timer.php#L126-L162","documentation":"Timer::add() validates its first argument and rejects negative intervals: the event loop can only schedule callbacks at 'now or later'. A negative float means the computed deadline is in the past, which is almost always a bug in the caller's math.","triggerScenarios":"Passing a computed delay that went negative, e.g. Timer::add($nextRunTimestamp - time(), ...) where the next run already passed; passing -1 as an 'immediate' flag; passing an absolute Unix timestamp instead of an offset in seconds.","commonSituations":"Cron-style schedulers computing 'seconds until next minute/hour' with a race that yields -1; mixing time() and microtime(true) units; DST or clock-skew corrections making a stored deadline earlier than now.","solutions":["Clamp the interval before scheduling: Timer::add(max(0.001, $interval), ...)","Fix the computation: subtract once and re-check, or loop while ($next <= time()) $next += $period before computing the delta","Make sure you pass a relative offset in seconds (float), never an absolute timestamp"],"exampleFix":"// before\n$delta = $nextRun - time(); // can be -3 when the slot just passed\nTimer::add($delta, fn() => run()); // throws '$timeInterval can not less than 0'\n\n// after\n$delta = max(0.001, $nextRun - time());\nTimer::add($delta, fn() => run());","handlingStrategy":"validation","validationCode":"$interval = $nextRun - time(); // computed\nTimer::add(max(0.001, (float)$interval), $cb);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always clamp computed delays with max() before passing to Timer::add","Advance past-due cron slots in a while-loop before computing the delta","Pass relative seconds, never absolute timestamps"],"tags":["php","workerman","timer","scheduling","argument-validation"],"backgroundTag":"invalid-interval-value","analyzedSha":"1391112a61d23020e11e7b89f17050f6cfaea431","analyzedAt":"2026-08-21T02:05:46.744Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}