walkor/workerman · error · RuntimeException
$timeInterval can not less than 0
Error message
$timeInterval can not less than 0
What it means
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.
Source
Thrown at src/Timer.php:144
if (!self::$event) {
pcntl_alarm(1);
self::tick();
}
}
/**
* Add a timer.
*
* @param float $timeInterval
* @param callable $func
* @param null|array $args
* @param bool $persistent
* @return int
*/
public static function add(float $timeInterval, callable $func, ?array $args = [], bool $persistent = true): int
{
if ($timeInterval < 0) {
throw new RuntimeException('$timeInterval can not less than 0');
}
if ($args === null) {
$args = [];
}
if (self::$event) {
return $persistent ? self::$event->repeat($timeInterval, $func, $args) : self::$event->delay($timeInterval, $func, $args);
}
// If not workerman runtime just return.
if (!Worker::getAllWorkers()) {
throw new RuntimeException('Timer can only be used in workerman running environment');
}
if (empty(self::$tasks)) {
pcntl_alarm(1);
}View on GitHub (pinned to 1391112a61)
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
Example fix
// before $delta = $nextRun - time(); // can be -3 when the slot just passed Timer::add($delta, fn() => run()); // throws '$timeInterval can not less than 0' // after $delta = max(0.001, $nextRun - time()); Timer::add($delta, fn() => run());
Defensive patterns
Strategy: validation
Validate before calling
$interval = $nextRun - time(); // computed Timer::add(max(0.001, (float)$interval), $cb);
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Timer can only be used in workerman running environment
- Event::addTimer($delay) failed
- Event::addTimer($interval) failed
- Bad remoteAddress
- Invalid protocol scheme '$scheme'
AI-assisted analysis of walkor/workerman@1391112a61 (2026-08-21).
Data as JSON: /api/errors/fdafc54794cb554b.
Report an issue: GitHub.