{"record":{"id":"6437af57aaa71ccb","repo":"sebastianbergmann/phpunit","slug":"value-for-nanoseconds-must-not-be-greater-than-999-6437af","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/Duration.php","lineNumber":162,"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":144,"sourceCodeEnd":168,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Event/Value/Telemetry/Duration.php#L144-L168","documentation":"Duration's constructor caps nanoseconds at 999999999; larger values mean the caller did not normalize carries into seconds. Common sources are conversions into the nanoseconds slot from total-nanosecond or microsecond values, or re-creating a Duration from its asFloat()/asString() output without splitting.","triggerScenarios":"Duration::fromSecondsAndNanoseconds(0, $microseconds * 1000000) (wrong factor; should be * 1000); passing an hrtime(true) difference into nanoseconds; parsing a float like 1.5 seconds into (0 seconds, 1500000000 nanoseconds).","commonSituations":"Custom stopwatch or reporter code bridging microsecond-precision APIs (getrusage, microtime) and nanosecond-precision values; serializing durations and reconstructing them; test data builders for telemetry fixtures.","solutions":["Normalize before constructing: $seconds = intdiv($nanos, 1000000000); $nanos %= 1000000000;","Convert microseconds to nanoseconds with * 1000, milliseconds with * 1000000 only after splitting totals.","Build aggregates with Duration::add(), which performs the >= 1000000000 carry itself."],"exampleFix":"// before\n$micros = (int) $usage['ru_utime.tv_usec'];\n$d = Duration::fromSecondsAndNanoseconds(0, $micros * 1000000); // wrong factor\n\n// after\n$nanos = $micros * 1000;\n$d = Duration::fromSecondsAndNanoseconds(\n    intdiv($nanos, 1000000000),\n    $nanos % 1000000000,\n);","handlingStrategy":"validation","validationCode":"$nanoseconds = $microseconds * 1000; // correct us -> ns factor\n\n$duration = Duration::fromSecondsAndNanoseconds(\n    intdiv($nanoseconds, 1000000000),\n    $nanoseconds % 1000000000,\n);","typeGuard":"function isNormalizedNanoseconds(int $nanoseconds): bool\n{\n    return $nanoseconds >= 0 && $nanoseconds <= 999999999;\n}","tryCatchPattern":null,"preventionTips":["Never pass raw totals into the nanoseconds slot; split with intdiv/modulo 1000000000.","Double-check unit factors when bridging microsecond and nanosecond APIs.","Use Duration::add() for aggregation; it carries seconds automatically."],"tags":["phpunit","telemetry","value-object","duration","unit-conversion","php"],"backgroundTag":"nanoseconds-overflow","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}