{"record":{"id":"14c30faab1de5fd4","repo":"symfony/finder","slug":"the-ignorevcsignored-option-cannot-be-used-by-the-finder-as","errorCode":null,"errorMessage":"The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable.","messagePattern":"The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"(.+?)\" file is not readable\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"Iterator/VcsIgnoredFilterIterator.php","lineNumber":159,"sourceCode":"    }\n\n    /**\n     * Returns the rules of a .gitignore file, last one first, as [regex, isNegated, isDirOnly] tuples.\n     *\n     * @return list<array{0: string, 1: bool, 2: bool}>|null\n     */\n    private function readGitignoreFile(string $path): ?array\n    {\n        if (\\array_key_exists($path, $this->gitignoreFilesCache)) {\n            return $this->gitignoreFilesCache[$path];\n        }\n\n        if (!file_exists($path)) {\n            return $this->gitignoreFilesCache[$path] = null;\n        }\n\n        if (!is_file($path) || !is_readable($path)) {\n            throw new \\RuntimeException(\"The \\\"ignoreVCSIgnored\\\" option cannot be used by the Finder as the \\\"{$path}\\\" file is not readable.\");\n        }\n\n        $rules = [];\n\n        foreach (preg_split('~\\r\\n?|\\n~', file_get_contents($path)) as $line) {\n            // only a line starting with \"#\" is a comment, and only trailing spaces are stripped\n            if (str_starts_with($line, '#')) {\n                continue;\n            }\n\n            $line = preg_replace('~(?<!\\\\\\\\) +$~', '', $line);\n\n            if ($isNegated = str_starts_with($line, '!')) {\n                $line = substr($line, 1);\n            }\n\n            if ($isDirOnly = str_ends_with($line, '/')) {\n                $line = substr($line, 0, -1);","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/symfony/finder/blob/4d6c057bfd67c5a93e8025c85ca9364cba7e260a/Iterator/VcsIgnoredFilterIterator.php#L141-L177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n$finder = Finder::create()\n    ->in($projectDir)\n    ->ignoreVCSIgnored(true);\n\n// after: verify readability up front, or disable the option\nforeach (Finder::create()->directories()->in($projectDir) as $dir) {\n    $gi = $dir->getRealPath() . '/.gitignore';\n    if (file_exists($gi) && (!is_file($gi) || !is_readable($gi))) {\n        chmod($gi, 0644); // or skip handling manually\n    }\n}\n$finder = Finder::create()\n    ->in($projectDir)\n    ->ignoreVCSIgnored(true);","handlingStrategy":"try-catch","validationCode":"function ensureGitignoresReadable(string $dir): void {\n    $it = new \\RecursiveIteratorIterator(\n        new \\RecursiveDirectoryIterator($dir, \\FilesystemIterator::SKIP_DOTS)\n    );\n    foreach ($it as $f) {\n        if ($f->getFilename() === '.gitignore'\n            && (!is_file($f->getPathname()) || !is_readable($f->getPathname()))) {\n            throw new \\RuntimeException(\"Unreadable .gitignore: \" . $f->getPathname());\n        }\n    }\n}\nensureGitignoresReadable($projectDir);","typeGuard":"function isReadableGitignore(string $path): bool {\n    return file_exists($path) && is_file($path) && is_readable($path);\n}\n\n// usage before iterating:\n// if (!isReadableGitignore($baseDir . '/.gitignore')) { /* fix perms or skip */ }","tryCatchPattern":"try {\n    $files = iterator_to_array(\n        Finder::create()->in($dir)->ignoreVCSIgnored(true)->files()\n    );\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'ignoreVCSIgnored')) {\n        $files = iterator_to_array(\n            Finder::create()->in($dir)->files() // fallback: no gitignore filtering\n        );\n    } else {\n        throw $e;\n    }\n}","preventionTips":["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."],"tags":["php","symfony","finder","filesystem","permissions","gitignore"],"backgroundTag":"file-read-failed","analyzedSha":"4d6c057bfd67c5a93e8025c85ca9364cba7e260a","analyzedAt":"2026-09-13T07:49:33.433Z","contentChangedAt":"2026-09-13T07:49:33.433Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}