sebastianbergmann/phpunit · error · PHPUnit\Event\RuntimeException
getrusage() did not return the expected keys "%s" and "%s".
Error message
getrusage() did not return the expected keys "%s" and "%s".
What it means
After a successful getrusage(), SystemCpuTimeMeter expects the POSIX keys 'ru_utime.tv_sec'/'ru_utime.tv_usec' (or 'ru_stime.*') in the returned array. If either key is missing, it throws this RuntimeException. Like the other getrusage guards it is @codeCoverageIgnore'd because real PHP always returns those keys; only a non-standard or intercepted getrusage() returning a different array shape can trigger it.
Source
Thrown at src/Event/Value/Telemetry/SystemCpuTimeMeter.php:58
/**
* @param 'ru_stime.tv_sec'|'ru_utime.tv_sec' $secondsKey
* @param 'ru_stime.tv_usec'|'ru_utime.tv_usec' $microsecondsKey
*
* @throws RuntimeException
*/
private function cpuTime(string $secondsKey, string $microsecondsKey): CpuTime
{
$usage = getrusage();
if ($usage === false) {
// @codeCoverageIgnoreStart
throw new RuntimeException('getrusage() failed.');
// @codeCoverageIgnoreEnd
}
if (!isset($usage[$secondsKey]) || !isset($usage[$microsecondsKey])) {
// @codeCoverageIgnoreStart
throw new RuntimeException(
sprintf(
'getrusage() did not return the expected keys "%s" and "%s".',
$secondsKey,
$microsecondsKey,
),
);
// @codeCoverageIgnoreEnd
}
$seconds = $usage[$secondsKey];
$microseconds = $usage[$microsecondsKey];
if (!is_int($seconds) || !is_int($microseconds)) {
// @codeCoverageIgnoreStart
throw new RuntimeException(
sprintf(
'getrusage() returned non-integer values for "%s" and/or "%s".',
$secondsKey,View on GitHub (pinned to f123cdb2a2)
Solutions
- Inspect what getrusage() actually returns in that environment: php -r 'var_dump(array_keys(getrusage()));' and compare against ru_utime.tv_sec/ru_utime.tv_usec/ru_stime.*.
- Fix or remove the function override so the stock array shape is preserved.
- Catch PHPUnit\Event\RuntimeException around the meter calls and skip CPU-time reporting when the environment is known to be constrained.
Example fix
// stub fix: return the POSIX shape
// before
function getrusage(): array { return ['utime_sec' => 1, 'utime_usec' => 500]; }
// after
function getrusage(): array { return ['ru_utime.tv_sec' => 1, 'ru_utime.tv_usec' => 500, 'ru_stime.tv_sec' => 0, 'ru_stime.tv_usec' => 0]; } Defensive patterns
Strategy: fallback
Validate before calling
$usage = getrusage();
if ($usage === false || !isset($usage['ru_utime.tv_sec'], $usage['ru_utime.tv_usec'])) {
// rusage array shape unsupported here; skip CPU-time telemetry
} Try / catch
try {
$cpu = $meter->userCpuTime();
} catch (PHPUnit\Event\RuntimeException $e) {
// Unexpected getrusage() shape: degrade to time-only reporting
} Prevention
- Make any getrusage() test double return the full POSIX key set (ru_utime.tv_sec, ru_utime.tv_usec, ru_stime.tv_sec, ru_stime.tv_usec).
- Verify the rusage array shape when PHP or SAPI changes.
- Treat CPU telemetry as optional and guard it in environment-portable runners.
When it happens
Trigger: A shadowed/mocked getrusage() (namespace 'use function' trick, uopz, runkit7) returning a partial or renamed array; platform abstractions or patched PHP builds that alter the rusage array structure.
Common situations: Unit tests of telemetry code with hand-rolled getrusage stubs; exotic SAPIs; debugging sessions where a debugger extension rewrites native function results.
Related errors
- getrusage() failed.
- getrusage() returned non-integer values for "%s" and/or "%s"
- Value for %s must not be negative.
- Value for nanoseconds must not be greater than 999999999.
- Value for %s must not be negative.
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/1dcec2ce4f91e2d8.
Report an issue: GitHub.