symfony/finder · error · Symfony\Component\Finder\Exception\AccessDeniedException
$e->getMessage() (dynamic; wrapped…
Error message
$e->getMessage() (dynamic; wrapped \UnexpectedValueException message, rethrown as AccessDeniedException)
What it means
RecursiveDirectoryIterator::getChildren() wraps any \UnexpectedValueException thrown by the underlying SplFilesystemIterator (typically when a subdirectory cannot be opened or read) into Symfony's AccessDeniedException, preserving message, code, and previous exception. The library throws it so consumers can distinguish permission/unreadable-directory failures during filesystem traversal.
Solutions
- Catch AccessDeniedException (or use the ignoreUnreadableDirs constructor flag / Finder's ignoreUnreadableDirs()) so iteration skips unreadable directories
- Fix filesystem permissions (chmod/chown) so the iterating user can read the affected directory
- Check that the directory still exists before descending; re-stat or refresh the iterator
- Inspect the wrapped previous exception to confirm it is an UnexpectedValueException from SplFilesystemIterator open failure
Example fix
// before
foreach ($iterator as $file) {
$children = $iterator->getChildren(); // throws AccessDeniedException
}
// after
$iterator = new \Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator($path, $flags, true); // ignoreUnreadableDirs
// or
try {
$children = $iterator->getChildren();
} catch (AccessDeniedException $e) {
// skip unreadable directory
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!is_dir($dir) || !is_readable($dir)) { /* skip or fix perms */ } Type guard
function isReadableDir(string $path): bool { return is_dir($path) && is_readable($path); } Try / catch
try { $children = $iterator->getChildren(); } catch (\Symfony\Component\Finder\Exception\AccessDeniedException $e) { // skip unreadable dir } Prevention
- Enable ignoreUnreadableDirs (or Finder::ignoreUnreadableDirs()) for resilient traversal
- Run the process as a user with read access to all scanned trees
- Avoid scanning directories that other processes delete/rename concurrently
- Check is_readable() on directories before descending
When it happens
Trigger: Calling getChildren() on a directory entry whose underlying open fails: unreadable directory permissions, a directory removed between iteration steps, or an entry that disappears during iteration (race with concurrent deletion).
Common situations: Scanning vendor or cache directories with restrictive permissions, iterating directories changed by other processes (build cleanup, tmp reaping), running as a user without read access to nested directories, containers with read-only mounts.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- This iterator only support returning current as fileinfo.
- The "ignoreVCSIgnored" option cannot be used by the Finder…
AI-assisted analysis of symfony/finder@4d6c057bfd (2026-09-13).
Data as JSON: /api/errors/37c03b044e3742a2.
Report an issue: GitHub.
Appendix: source
Thrown at Iterator/RecursiveDirectoryIterator.php:111
/**
* @throws AccessDeniedException
*/
public function getChildren(): \RecursiveDirectoryIterator
{
try {
$children = parent::getChildren();
if ($children instanceof self) {
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
// performance optimization to avoid redoing the same work in all children
$children->rootPath = $this->rootPath;
}
return $children;
} catch (\UnexpectedValueException $e) {
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
}
}
public function next(): void
{
$this->ignoreFirstRewind = false;
parent::next();
}
public function rewind(): void
{
// some streams like FTP are not rewindable, ignore the first rewind after creation,
// as newly created DirectoryIterator does not need to be rewound
if ($this->ignoreFirstRewind) {
$this->ignoreFirstRewind = false;
return;View on GitHub (pinned to 4d6c057bfd)