sebastianbergmann/phpunit · error · PHPUnit\Util\PHP\PhpProcessException
Unable to write temporary file
Error message
Unable to write temporary file
What it means
JobRunner::run() executes a test in a separate PHP process (#[RunInSeparateProcess], process isolation). It first writes the generated job code to a temporary file using tempnam(sys_get_temp_dir(), 'phpunit_') plus file_put_contents(); if either step fails it throws PhpProcessException('Unable to write temporary file'). This is an environment failure in the temp directory, not a problem with your test code.
Source
Thrown at src/Util/PHP/JobRunner.php:102
);
EventFacade::emitter()->childProcessFinished($job->reason(), $result->stdout(), $result->stderr());
}
/**
* @throws PhpProcessException
*/
public function run(Job $job): Result
{
$temporaryFile = null;
if ($job->hasInput()) {
$temporaryFile = tempnam(sys_get_temp_dir(), 'phpunit_');
if ($temporaryFile === false ||
file_put_contents($temporaryFile, $job->code()) === false) {
// @codeCoverageIgnoreStart
throw new PhpProcessException(
'Unable to write temporary file',
);
// @codeCoverageIgnoreEnd
}
$job = new Job(
$job->input(),
$job->reason(),
$job->phpSettings(),
$job->environmentVariables(),
$job->arguments(),
null,
$job->redirectErrors(),
$job->requiresXdebug(),
);
}
assert($temporaryFile !== '');View on GitHub (pinned to f123cdb2a2)
Solutions
- Point TMPDIR at a writable directory before running PHPUnit: `TMPDIR=/workspace/tmp vendor/bin/phpunit`
- In containers, mount a writable tmpfs on /tmp (for example `--tmpfs /tmp:rw` in docker run)
- Free disk space or raise the quota if the volume is full
- If process isolation is not strictly required for that test, remove #[RunInSeparateProcess] / the isolation setting so no temp job file is needed
Example fix
# before $ vendor/bin/phpunit --process-isolation # PhpProcessException: Unable to write temporary file (read-only /tmp) # after $ mkdir -p /workspace/tmp && TMPDIR=/workspace/tmp vendor/bin/phpunit --process-isolation
Defensive patterns
Strategy: try-catch
Validate before calling
if (!is_writable(sys_get_temp_dir())) {
throw new RuntimeException('Temp directory ' . sys_get_temp_dir() . ' is not writable; set TMPDIR');
} Try / catch
use PHPUnit\Util\PHP\PhpProcessException;
try {
$runner->run($job);
} catch (PhpProcessException $e) {
if ($e->getMessage() === 'Unable to write temporary file') {
// re-run with TMPDIR pointed at a writable dir, or skip process isolation
}
} Prevention
- Add a smoke check to the bootstrap: fail fast when is_writable(sys_get_temp_dir()) is false
- Export TMPDIR to a workspace-local directory in CI job definitions
- Keep a tmpfs mounted on /tmp in read-only containers
- Only use #[RunInSeparateProcess] where isolation is genuinely required
When it happens
Trigger: Running any test marked #[RunInSeparateProcess] (or with process isolation enabled globally) on a host where the temp directory is not writable: TMPDIR points somewhere unwritable, /tmp is a read-only filesystem, the disk is full, or open_basedir excludes the temp path.
Common situations: Hardened Docker images with a read-only root filesystem and no tmpfs on /tmp; CI runners with exhausted disk; misconfigured TMPDIR in systemd services or cron contexts; open_basedir shared-hosting style restrictions.
Related errors
- Unable to create temporary file for redirected output
- Unable to spawn worker process
- getrusage() failed.
- getrusage() did not return the expected keys "%s" and "%s".
- getrusage() returned non-integer values for "%s" and/or "%s"
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/319fad5c36c05d0f.
Report an issue: GitHub.