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

  1. Split totals first: $seconds = intdiv($nanos, 1000000000); $nanos %= 1000000000; then construct.
  2. When converting microseconds, multiply by exactly 1000 (the built-in SystemCpuTimeMeter does $microseconds * 1000).
  3. 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

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


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/0820a1e1fcc84dac. Report an issue: GitHub.