sebastianbergmann/phpunit · error · PHPUnit\Util\PHP\PhpProcessException

Unable to spawn worker process

Error message

Unable to spawn worker process

What it means

JobRunner::startProcess() spawns the child PHP process with proc_open(); when proc_open() does not return a resource it throws PhpProcessException('Unable to spawn worker process'). The job code was already written and the pipes prepared — only the actual process creation failed. Typical causes are an invalid or non-executable PHP binary, proc_open being disabled, or OS-level resource limits.

Source

Thrown at src/Util/PHP/JobRunner.php:223

        } else {
            $pipeSpec = [
                0 => ['pipe', 'r'],
                1 => ['pipe', 'w'],
                2 => ['pipe', 'w'],
            ];
        }

        $process = proc_open(
            $this->buildCommand($job, $temporaryFile),
            $pipeSpec,
            $pipes,
            null,
            $environmentVariables,
        );

        if (!is_resource($process)) {
            // @codeCoverageIgnoreStart
            throw new PhpProcessException(
                'Unable to spawn worker process',
            );
            // @codeCoverageIgnoreEnd
        }

        Facade::emitter()->childProcessStarted($job->reason());

        return new RunningJob($process, $pipes, $mergedOutputStream, $temporaryFile);
    }

    /**
     * @return non-empty-list<string>
     */
    private function buildCommand(Job $job, ?string $file): array
    {
        $runtime     = new Runtime;
        $command     = [PHP_BINARY];
        $phpSettings = $job->phpSettings();

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Confirm the same PHP binary works where PHPUnit runs: `php -v` and `ls -l $(which php)`; fix PATH or install php-cli
  2. Check `php -i | grep disable_functions` for proc_open and have it removed from disable_functions (or switch to a host that allows it)
  3. Raise pid/fork limits (ulimit -u, container pids limit) or reduce parallel child usage
  4. If the sandbox forbids spawning processes, drop process isolation for those tests

Example fix

# before
$ php -r 'var_dump(function_exists("proc_open"));' # false
$ vendor/bin/phpunit --process-isolation
# PhpProcessException: Unable to spawn worker process

# after: enable proc_open (remove it from disable_functions in php.ini), then
$ vendor/bin/phpunit --process-isolation
Defensive patterns

Strategy: try-catch

Validate before calling

if (!function_exists('proc_open')) {
    throw new RuntimeException('proc_open is disabled; process isolation unavailable');
}
if (PHP_BINARY === false || !is_executable(PHP_BINARY)) {
    throw new RuntimeException('PHP CLI binary missing or not executable');
}

Try / catch

use PHPUnit\Util\PHP\PhpProcessException;

try {
    $runner->start($job);
} catch (PhpProcessException $e) {
    if ($e->getMessage() === 'Unable to spawn worker process') {
        // report environment problem; do not retry blindly
        throw new RuntimeException('Check PHP_BINARY, proc_open and pid limits', 0, $e);
    }
    throw $e;
}

Prevention

When it happens

Trigger: Running tests in separate processes when the PHP CLI binary used for children does not exist or is not executable, proc_open is listed in disable_functions, the process/fork limit (ulimit, cgroups PIDs controller) is hit, or a container seccomp/apparmor profile blocks process creation.

Common situations: Docker/production-derived images where the php binary lives at a different path than PHP_BINARY reports; shared hosting with proc_open disabled for security; CI containers with a low pids limit; memory exhaustion preventing fork.

Related errors


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