{"record":{"id":"0820a1e1fcc84dac","repo":"sebastianbergmann/phpunit","slug":"value-for-nanoseconds-must-not-be-greater-than-999","errorCode":null,"errorMessage":"Value for nanoseconds must not be greater than 999999999.","messagePattern":"Value for nanoseconds must not be greater than 999999999\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Event/Value/Telemetry/CpuTime.php","lineNumber":125,"sourceCode":"    private function ensureNotNegative(int $value, string $type): void\n    {\n        if ($value < 0) {\n            throw new InvalidArgumentException(\n                sprintf(\n                    'Value for %s must not be negative.',\n                    $type,\n                ),\n            );\n        }\n    }\n\n    /**\n     * @throws InvalidArgumentException\n     */\n    private function ensureNanoSecondsInRange(int $nanoseconds): void\n    {\n        if ($nanoseconds > 999999999) {\n            throw new InvalidArgumentException(\n                'Value for nanoseconds must not be greater than 999999999.',\n            );\n        }\n    }\n}\n","sourceCodeStart":107,"sourceCodeEnd":131,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Event/Value/Telemetry/CpuTime.php#L107-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom CpuTimeMeter implementations; converting stopwatch output (float seconds or microsecond integers) into CpuTime; porting telemetry code between nanosecond and microsecond APIs.","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."],"exampleFix":"// before\n$diffNanos = hrtime(true) - $t0;\n$cpu = CpuTime::fromSecondsAndNanoseconds(0, $diffNanos); // > 999999999\n\n// after\n$diffNanos = hrtime(true) - $t0;\n$cpu = CpuTime::fromSecondsAndNanoseconds(\n    intdiv($diffNanos, 1000000000),\n    $diffNanos % 1000000000,\n);","handlingStrategy":"validation","validationCode":"$seconds     = intdiv($totalNanos, 1000000000);\n$nanoseconds = $totalNanos % 1000000000;\n\n$cpu = CpuTime::fromSecondsAndNanoseconds($seconds, $nanoseconds); // nanoseconds < 1e9 guaranteed","typeGuard":"function isNormalizedNanoseconds(int $nanoseconds): bool\n{\n    return $nanoseconds >= 0 && $nanoseconds <= 999999999;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["phpunit","telemetry","value-object","cpu-time","unit-conversion","php"],"backgroundTag":"nanoseconds-overflow","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}