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
HRTime's constructor caps nanoseconds at 999999999 (ensureNanoSecondsInRange()). Because hrtime(true) returns one total-nanoseconds integer, feeding that value (or any unsplit difference of such totals) into the nanoseconds parameter of fromSecondsAndNanoseconds() is the classic trigger.
Source
Thrown at src/Event/Value/Telemetry/HRTime.php:106
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 before constructing: $nanos = hrtime(true) - $t0; then seconds = intdiv($nanos, 1000000000), nanoseconds = $nanos % 1000000000.
- Prefer hrtime(false) which already returns the [seconds, nanoseconds] pair the constructor wants.
- Watch unit factors: microseconds need * 1000 to become nanoseconds, not * 1000000.
Example fix
// before $total = hrtime(true); $stamp = HRTime::fromSecondsAndNanoseconds(0, $total); // way over 999999999 // after [$seconds, $nanoseconds] = hrtime(false); $stamp = HRTime::fromSecondsAndNanoseconds($seconds, $nanoseconds);
Defensive patterns
Strategy: validation
Validate before calling
[$seconds, $nanoseconds] = hrtime(false); // already a normalized pair // or, from a total: $total = hrtime(true) - $t0; $seconds = intdiv($total, 1000000000); $nanoseconds = $total % 1000000000; $stamp = HRTime::fromSecondsAndNanoseconds($seconds, $nanoseconds);
Type guard
function isNormalizedNanoseconds(int $nanoseconds): bool
{
return $nanoseconds >= 0 && $nanoseconds <= 999999999;
} Prevention
- Prefer hrtime(false) over hrtime(true) when building HRTime values.
- Split any hrtime(true) total with intdiv/modulo 1000000000 before constructing.
- Keep microsecond-to-nanosecond factors straight (* 1000).
When it happens
Trigger: HRTime::fromSecondsAndNanoseconds(0, hrtime(true)); computing a difference of two hrtime(true) totals and passing it as nanoseconds; converting a microsecond value with a 1000000 factor.
Common situations: Custom stopwatch/telemetry code switching between hrtime(true) and the (seconds, nanoseconds) pair; adapting example code written for total-nanosecond APIs; test fixtures generated from raw timestamps.
Related errors
- 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.
- Value for %s must not be negative.
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/4df5f70c35b80a9b.
Report an issue: GitHub.