sebastianbergmann/phpunit · error · PhptExternalFileCannotBeLoadedException
Could not load --%s-- %s for PHPT file
Error message
Could not load --%s-- %s for PHPT file
What it means
parseExternal() resolves the --FILE_EXTERNAL--, --EXPECT_EXTERNAL--, --EXPECTF_EXTERNAL-- and --EXPECTREGEX_EXTERNAL-- values: the referenced file must exist in the same directory as the .phpt file (path is testDirectory . filename, so references are relative to the test, never to the CWD) and be readable; otherwise PhptExternalFileCannotBeLoadedException('Could not load --%s-- %s for PHPT file') is thrown. Both is_file() and is_readable() must pass after trim()ing the value.
Source
Thrown at src/Runner/Phpt/Parser.php:262
*/
private function parseExternal(string $phptFile, array &$sections): void
{
$allowSections = [
'FILE',
'EXPECT',
'EXPECTF',
'EXPECTREGEX',
];
$testDirectory = dirname($phptFile) . DIRECTORY_SEPARATOR;
foreach ($allowSections as $section) {
if (isset($sections[$section . '_EXTERNAL'])) {
$externalFilename = trim($sections[$section . '_EXTERNAL']);
if (!is_file($testDirectory . $externalFilename) ||
!is_readable($testDirectory . $externalFilename)) {
throw new PhptExternalFileCannotBeLoadedException(
$section,
$testDirectory . $externalFilename,
);
}
$externalPath = $testDirectory . $externalFilename;
$contents = file_get_contents($externalPath);
assert($contents !== false);
$sections[$section] = $contents;
if ($section === 'FILE') {
$resolvedPath = realpath($externalPath);
assert(is_string($resolvedPath));
assert($resolvedPath !== '');
View on GitHub (pinned to f123cdb2a2)
Solutions
- Check that the referenced file exists in the same directory as the .phpt file and that its name (including case) matches exactly.
- Ship or restore the missing external fixture in your test distribution.
- Fix permissions so the PHP process can read the file (is_readable must pass, not just file_exists).
Example fix
-- before --FILE_EXTERNAL-- example_code.php.txt % actual file is example_code.php -- after --FILE_EXTERNAL-- example_code.php
Defensive patterns
Strategy: validation
Validate before calling
function assertPhptExternalFilesExist(string $phptFile): void
{
$dir = dirname($phptFile) . DIRECTORY_SEPARATOR;
foreach (file($phptFile) as $line) {
if (preg_match('/^--(FILE|EXPECT|EXPECTF|EXPECTREGEX)_EXTERNAL--/', $line, $m) === 0) {
continue;
}
// value = next line(s); simplified: assume single-line value follows
}
$sections = (new \PHPUnit\Runner\Phpt\Parser())->parse($phptFile); // not reached if invalid
}
// simpler targeted check before running a suite:
foreach (glob('tests/*.phpt') as $phpt) {
$dir = dirname($phpt) . DIRECTORY_SEPARATOR;
$body = file_get_contents($phpt);
foreach (['FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX'] as $s) {
if (preg_match('/--' . $s . '_EXTERNAL--\R\s*(\S+)/', $body, $m) === 1
&& (!is_file($dir . $m[1]) || !is_readable($dir . $m[1]))) {
throw new RuntimeException("Missing external fixture: {$dir}{$m[1]}");
}
}
} Try / catch
try {
(new \PHPUnit\Runner\Phpt\Parser())->parse($phptFile);
} catch (\PHPUnit\Runner\Phpt\PhptExternalFileCannotBeLoadedException $e) {
// message names the section and expected path; restore the fixture and retry
} Prevention
- Keep external fixture files co-located with the .phpt file and reference them by bare filename only.
- Add *.php fixture files next to *.phpt to your distribution/CI artifact list so they are not filtered out.
- Watch for case mismatches when developing on macOS/Windows and running on Linux.
When it happens
Trigger: An external section references a file that does not exist next to the .phpt file (typo, wrong case, missing from the distribution) or exists but is not readable by the PHP process; a stray trailing character in the section value makes the trimmed filename wrong.
Common situations: Packaging PHPT suites where external fixture files were excluded from the dist/zipball; case-sensitivity differences between macOS and Linux filesystems; checkouts or containers where file permissions deny read access.
Related errors
- File referenced by --FILE_EXTERNAL-- section is empty
- --%s-- is not a valid PHPT section
- --%s-- section occurs more than once
- PHPT file must not contain text before its first section (li
- PHPUnit does not support PHPT --%s-- sections
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/14d75e09e86aaaa2.
Report an issue: GitHub.