sebastianbergmann/phpunit · error · InvalidArgumentException
Value for nanoseconds must not be greater than 999999999.
Error message
Value for nanoseconds must not be greater than 999999999.
What it means
CpuTime's constructor caps the nanoseconds component at 999999999 (ensureNanoSecondsInRange()); anything larger means the caller did not carry full seconds. The factory is fromSecondsAndNanoseconds(), so a raw total-nanoseconds value or a wrong microseconds-to-nanoseconds factor lands in the nanoseconds slot and trips this guard.
Source
Thrown at src/Event/Value/Telemetry/CpuTime.php:125
private function ensureNotNegative(int $value, string $type): void
{
if ($value < 0) {
throw new InvalidArgumentException(
sprintf(
'Value for %s must not be negative.',
$type,
),
);
}
}
/**
* @throws InvalidArgumentException
*/
private function ensureNanoSecondsInRange(int $nanoseconds): void
{
if ($nanoseconds > 999999999) {
throw new InvalidArgumentException(
'Value for nanoseconds must not be greater than 999999999.',
);
}
}
}
View on GitHub (pinned to f123cdb2a2)
Solutions
- Split totals first: $seconds = intdiv($nanos, 1000000000); $nanos %= 1000000000; then construct.
- When converting microseconds, multiply by exactly 1000 (the built-in SystemCpuTimeMeter does $microseconds * 1000).
- Prefer composing CpuTime objects via add() (which performs the carry) over manual arithmetic.
Example fix
// before
$diffNanos = hrtime(true) - $t0;
$cpu = CpuTime::fromSecondsAndNanoseconds(0, $diffNanos); // > 999999999
// after
$diffNanos = hrtime(true) - $t0;
$cpu = CpuTime::fromSecondsAndNanoseconds(
intdiv($diffNanos, 1000000000),
$diffNanos % 1000000000,
); Defensive patterns
Strategy: validation
Validate before calling
$seconds = intdiv($totalNanos, 1000000000); $nanoseconds = $totalNanos % 1000000000; $cpu = CpuTime::fromSecondsAndNanoseconds($seconds, $nanoseconds); // nanoseconds < 1e9 guaranteed
Type guard
function isNormalizedNanoseconds(int $nanoseconds): bool
{
return $nanoseconds >= 0 && $nanoseconds <= 999999999;
} Prevention
- Always split total-nanosecond values with intdiv/modulo 1000000000 before constructing.
- Convert microseconds to nanoseconds with * 1000 (not * 1000000).
- Prefer CpuTime::add() over manual nanosecond arithmetic; it performs the carry.
When it happens
Trigger: CpuTime::fromSecondsAndNanoseconds(0, $hrtimeDiffNanos) where $hrtimeDiffNanos is a full hrtime(true) difference; a custom meter converting getrusage() microseconds with 1000000 instead of 1000; adding raw nanosecond timestamps into the second parameter.
Common situations: Custom CpuTimeMeter implementations; converting stopwatch output (float seconds or microsecond integers) into CpuTime; porting telemetry code between nanosecond and microsecond APIs.
Related errors
- Value for %s must not be negative.
- Value for nanoseconds must not be greater than 999999999.
- Value for nanoseconds must not be greater than 999999999.
- Value for %s must not be negative.
- Value for %s must not be negative.
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/0820a1e1fcc84dac.
Report an issue: GitHub.