{"record":{"id":"b6e2f3f7da03a7f5","repo":"briannesbitt/Carbon","slug":"expected-positive-number-of-seconds-seconds","errorCode":null,"errorMessage":"Expected positive number of seconds, '.$seconds.' given","messagePattern":"Expected positive number of seconds, '\\.\\$seconds\\.' given","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Carbon/WrapperClock.php","lineNumber":122,"sourceCode":"            ? ($timezone === null ? $now : $now->setTimezone($timezone))\n            : $this->dateAsCarbon($now, $timezone);\n    }\n\n    private function dateAsCarbon(DateTimeInterface $date, DateTimeZone|string|int|null $timezone): CarbonInterface\n    {\n        return $date instanceof DateTimeImmutable\n            ? new CarbonImmutable($date, $timezone)\n            : new Carbon($date, $timezone);\n    }\n\n    public function sleep(float|int $seconds): void\n    {\n        if ($seconds === 0 || $seconds === 0.0) {\n            return;\n        }\n\n        if ($seconds < 0) {\n            throw new RuntimeException('Expected positive number of seconds, '.$seconds.' given');\n        }\n\n        if ($this->currentClock instanceof DateTimeInterface) {\n            $this->currentClock = $this->addSeconds($this->currentClock, $seconds);\n\n            return;\n        }\n\n        if ($this->currentClock instanceof ClockInterface) {\n            $this->currentClock->sleep($seconds);\n\n            return;\n        }\n\n        $this->currentClock = $this->addSeconds($this->currentClock->now(), $seconds);\n    }\n\n    public function withTimeZone(DateTimeZone|string $timezone): static","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/briannesbitt/Carbon/blob/b13f05955dcfd7da71d60af745fd148cbdb73505/src/Carbon/WrapperClock.php#L104-L140","documentation":"WrapperClock::sleep() advances (or really sleeps, depending on the wrapped clock) by the given seconds; zero is a permitted no-op but any negative duration is meaningless for sleeping, so it throws RuntimeException. Because WrapperClock can wrap a real Symfony/PSR clock or a frozen DateTime/test factory, this guard protects both real sleep() and simulated time from moving backwards.","triggerScenarios":"$clock->sleep(-1) directly; $clock->sleep($releaseAt - Carbon::now()->getTimestamp()) when the release moment already passed (negative difference); retry/backoff helpers computing $deadline - microtime(true) after a slow attempt; passing -0.5 floats from delta calculations; fuzz tests feeding boundary values expecting 0 to be the floor.","commonSituations":"Rate-limiter or lock-wait code where the target timestamp expired between computing and sleeping; concurrency races that make a computed delay negative; tests switching from a real clock to MockClock/WrapperClock exposing pre-existing negative-delay paths; timeouts configured as 'already elapsed'.","solutions":["Clamp the delay before sleeping: $clock->sleep(max(0, $delay))","If the deadline already passed, branch explicitly (skip sleeping, log, or fail) instead of relying on sleep to signal it","Compute delays as float seconds from a single now() reading taken as late as possible to shrink the race window","Catch RuntimeException around third-party sleep calls and treat it as 'deadline passed' if clamping is not acceptable"],"exampleFix":"// before\n$clock->sleep($resumeAt - $clock->now()->getTimestamp());\n\n// after\n$delay = max(0, $resumeAt - $clock->now()->getTimestamp());\nif ($delay === 0 && $resumeAt < $clock->now()->getTimestamp()) {\n    // deadline already passed - decide explicitly\n}\n$clock->sleep($delay);","handlingStrategy":"validation","validationCode":"$delay = $resumeAt - $clock->now()->getTimestamp();\nif ($delay < 0) {\n    // deadline already passed - skip sleeping and branch explicitly\n    return $onAlreadyDue();\n}\n$clock->sleep($delay);","typeGuard":"function isNonNegativeDelay(float|int $seconds): bool\n{\n    return $seconds >= 0;\n}","tryCatchPattern":"try {\n    $clock->sleep($delay);\n} catch (\\RuntimeException $e) {\n    // negative delay means deadline passed mid-computation\n    if ($delay < 0) {\n        return; // proceed immediately\n    }\n    throw $e;\n}","preventionTips":["Always clamp: sleep(max(0, $delay)) - zero is an accepted no-op","Take the now() reading as late as possible and from the same clock you sleep on","Treat a negative computed delay as a signal the deadline expired, not as an error to silence"],"tags":["php","carbon","clock","sleep","rate-limiting"],"backgroundTag":"negative-sleep-duration","analyzedSha":"b13f05955dcfd7da71d60af745fd148cbdb73505","analyzedAt":"2026-08-17T04:40:56.953Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}