sebastianbergmann/phpunit · error · PHPUnit\TextUI\RuntimeException
Cannot read from %s
Error message
Cannot read from %s
What it means
When --test-file-list is used, TestSuiteBuilder::build() first checks is_file() on the list file itself; if the path is not an existing regular file (missing, or a directory), it throws RuntimeException('Cannot read from ...'). The list file must be a plain text file containing one test file path per line.
Source
Thrown at src/TextUI/Configuration/TestSuiteBuilder.php:86
if ($configuration->hasCliArguments() || $configuration->hasTestFilesFile()) {
$arguments = [];
if ($configuration->hasCliArguments()) {
foreach ($configuration->cliArguments() as $cliArgument) {
$argument = realpath($cliArgument);
if ($argument === false) {
throw new TestFileNotFoundException($cliArgument);
}
$arguments[] = $argument;
}
}
if ($configuration->hasTestFilesFile()) {
if (!is_file($configuration->testFilesFile())) {
throw new RuntimeException('Cannot read from ' . $configuration->testFilesFile());
}
$directory = dirname($configuration->testFilesFile()) . DIRECTORY_SEPARATOR;
$fileLines = file($configuration->testFilesFile());
// @codeCoverageIgnoreStart
if ($fileLines === false) {
throw new RuntimeException('Cannot read from ' . $configuration->testFilesFile());
}
// @codeCoverageIgnoreEnd
foreach ($fileLines as $file) {
$file = trim($file);
$argument = realpath($file);
if ($argument === false) {
$argument = realpath($directory . $file);View on GitHub (pinned to f123cdb2a2)
Solutions
- Point --test-file-list at an existing text file with one test path per line
- Make the generating step fail loudly and verify the file exists before invoking phpunit: `test -s changed-tests.txt`
- Use an absolute path in CI to avoid cwd surprises
Example fix
# before (directory passed by mistake) vendor/bin/phpunit --test-file-list=tests/ # after git diff --name-only main -- 'tests/*Test.php' > changed-tests.txt vendor/bin/phpunit --test-file-list=changed-tests.txt
Defensive patterns
Strategy: validation
Validate before calling
$listFile = 'changed-tests.txt';
if (!is_file($listFile) || !is_readable($listFile)) {
fwrite(STDERR, "--test-file-list target missing or unreadable: {$listFile}" . PHP_EOL);
exit(2);
}
// shell: test -s "$list" || { echo "list generation failed"; exit 2; } Try / catch
try {
(new \PHPUnit\TextUI\Configuration\TestSuiteBuilder)->build($configuration);
} catch (\RuntimeException $e) {
if (str_starts_with($e->getMessage(), 'Cannot read from ')) {
// the --test-file-list path is not a readable regular file; fix the path/generation step
}
} Prevention
- --test-file-list takes a plain text file of paths, not a directory
- Make the list-generation step fail loudly and assert the artifact exists before running tests
- Use absolute paths in CI to eliminate cwd ambiguity
When it happens
Trigger: `vendor/bin/phpunit --test-file-list=tests/` (passing a directory instead of a file); a typo'd path; the list file was supposed to be generated by a previous pipeline step that failed silently; empty CI variable expanding to a bare or wrong path.
Common situations: Assuming the option accepts a directory; CI artifacts (the list) not uploaded between jobs; path relative to a different cwd.
Related errors
- Test file "%s" not found
- Class %s cannot be found in %s
- Cannot read from {file}
- Cannot open bootstrap script "%s"
- unrecognized --order-by option: %s
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/ceb47bab6565474b.
Report an issue: GitHub.