symfony/finder · error · RuntimeException
The "ignoreVCSIgnored" option cannot be used by the Finder…
Error message
The "ignoreVCSIgnored" option cannot be used by the Finder as the "{$path}" file is not readable. What it means
Symfony Finder's `ignoreVCSIgnored()` option filters files using .gitignore rules. While iterating, `VcsIgnoredFilterIterator::isIgnored()` walks the file's parent directories and calls `readGitignoreFile()` to parse each `.gitignore` it finds. When a `.gitignore` path exists but is not a regular readable file (e.g. a directory, or a file the PHP process lacks permission to read), the filter throws this RuntimeException because the ignore rules cannot be evaluated safely.
Solutions
- Check the reported path: `ls -la` it — if `.gitignore` is a directory, a broken symlink, or has unreadable permissions, remove or fix it (`chmod u+r .gitignore`, `rm -rf .gitignore` if it is a directory).
- If the file must stay restricted, run the PHP process as a user with read access to all `.gitignore` files under the scanned tree.
- If you don't need gitignore semantics, drop `->ignoreVCSIgnored()` from the Finder configuration so the filter is never attached.
- Pre-clean the scanned tree: ensure every ancestor directory up to the VCS root contains a readable regular-file `.gitignore` or none at all.
- Wrap iteration in try/catch for \RuntimeException and fall back to a Finder without ignoreVCSIgnored.
Example fix
// before
$finder = Finder::create()
->in($projectDir)
->ignoreVCSIgnored(true);
// after: verify readability up front, or disable the option
foreach (Finder::create()->directories()->in($projectDir) as $dir) {
$gi = $dir->getRealPath() . '/.gitignore';
if (file_exists($gi) && (!is_file($gi) || !is_readable($gi))) {
chmod($gi, 0644); // or skip handling manually
}
}
$finder = Finder::create()
->in($projectDir)
->ignoreVCSIgnored(true); Defensive patterns
Strategy: try-catch
Validate before calling
function ensureGitignoresReadable(string $dir): void {
$it = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS)
);
foreach ($it as $f) {
if ($f->getFilename() === '.gitignore'
&& (!is_file($f->getPathname()) || !is_readable($f->getPathname()))) {
throw new \RuntimeException("Unreadable .gitignore: " . $f->getPathname());
}
}
}
ensureGitignoresReadable($projectDir); Type guard
function isReadableGitignore(string $path): bool {
return file_exists($path) && is_file($path) && is_readable($path);
}
// usage before iterating:
// if (!isReadableGitignore($baseDir . '/.gitignore')) { /* fix perms or skip */ } Try / catch
try {
$files = iterator_to_array(
Finder::create()->in($dir)->ignoreVCSIgnored(true)->files()
);
} catch (\RuntimeException $e) {
if (str_contains($e->getMessage(), 'ignoreVCSIgnored')) {
$files = iterator_to_array(
Finder::create()->in($dir)->files() // fallback: no gitignore filtering
);
} else {
throw $e;
}
} Prevention
- Before using ignoreVCSIgnored(true), audit every directory from the scan root up to the VCS root for `.gitignore` files that are directories, symlinks, or unreadable.
- Run the PHP process with a user that owns or can read all files in the scanned tree (common issue in Docker: root vs www-data).
- Prefer excluding VCS paths with `exclude()` on known dirs if full gitignore semantics are not required.
- In CI, add a preflight step that runs `find . -name .gitignore ! -type f` and `find . -name .gitignore ! -readable` to catch anomalies early.
- Be aware of open_basedir / SELinux / container read-only mounts that make is_readable() false even for well-permissioned files.
When it happens
Trigger: Using `$finder->ignoreVCSIgnored(true)` (or ignoreDotFiles interplay) while iterating files under a tree where a directory-level `.gitignore` path exists but `is_file()` returns false or `is_readable()` returns false — e.g. `.gitignore` is a directory, a symlink to an unreadable target, has restrictive permissions (chmod 000 / root-owned in a container running as non-root), or open_basedir restrictions make it unreadable.
Common situations: Docker containers running Finder as www-data while `.gitignore` is owned by root with 0644/0600; a build step accidentally creating `.gitignore` as a directory; broken symlinks named `.gitignore`; CI environments with hardened permissions; NFS/Windows mounts where readability checks fail; macOS/Linux permission differences after `git clean` or template scaffolding.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- $e->getMessage() (dynamic; wrapped…
- Invalid operator " ".
- Don't understand " " as a number test.
- Invalid number " ".
- Invalid PHP callback.
AI-assisted analysis of symfony/finder@4d6c057bfd (2026-09-13).
Data as JSON: /api/errors/14c30faab1de5fd4.
Report an issue: GitHub.
Appendix: source
Thrown at Iterator/VcsIgnoredFilterIterator.php:159
}
/**
* Returns the rules of a .gitignore file, last one first, as [regex, isNegated, isDirOnly] tuples.
*
* @return list<array{0: string, 1: bool, 2: bool}>|null
*/
private function readGitignoreFile(string $path): ?array
{
if (\array_key_exists($path, $this->gitignoreFilesCache)) {
return $this->gitignoreFilesCache[$path];
}
if (!file_exists($path)) {
return $this->gitignoreFilesCache[$path] = null;
}
if (!is_file($path) || !is_readable($path)) {
throw new \RuntimeException("The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable.");
}
$rules = [];
foreach (preg_split('~\r\n?|\n~', file_get_contents($path)) as $line) {
// only a line starting with "#" is a comment, and only trailing spaces are stripped
if (str_starts_with($line, '#')) {
continue;
}
$line = preg_replace('~(?<!\\\\) +$~', '', $line);
if ($isNegated = str_starts_with($line, '!')) {
$line = substr($line, 1);
}
if ($isDirOnly = str_ends_with($line, '/')) {
$line = substr($line, 0, -1);View on GitHub (pinned to 4d6c057bfd)