uutils/coreutils · error · io::Error
Too many levels of symbolic links
Error message
Too many levels of symbolic links
What it means
uucore's canonicalize helper detects symbolic link loops while resolving a path. It tracks visited (file-information, remaining-path) pairs; if the same symlink is encountered again, resolution would never terminate, so it stops with 'Too many levels of symbolic links'. The comment notes ErrorKind::FilesystemLoop is intended once stable.
Solutions
- Fix the symlink cycle on disk (find it with `find -L dir -type l` or remove the offending link)
- Use the library's non-loop-following canonicalization or std::fs::canonicalize which reports ELOOP natively
- Catch the error and treat the path as unresolvable rather than retrying
Example fix
// before
ln -s loop loop; canonicalize("loop")
// after
rm loop; ln -s /real/target loop Defensive patterns
Strategy: try-catch
Validate before calling
// detect cycles cheaply before canonicalizing
fn has_symlink(p: &Path) -> bool { fs::symlink_metadata(p).map(|m| m.file_type().is_symlink()).unwrap_or(false) } Type guard
fn is_canonicalizable(p: &Path) -> bool {
std::fs::read_link(p).is_err() || std::fs::canonicalize(p).is_ok()
} Try / catch
match canonicalize(path) {
Ok(p) => use(p),
Err(e) if e.to_string().contains("Too many levels of symbolic links") => report_symlink_loop(path),
Err(e) => return Err(e.into()),
} Prevention
- Never create symlinks pointing to their own ancestor directory
- Run `find -L dir -type l` in CI to detect symlink cycles
- Prefer absolute symlink targets over relative ones that can loop
When it happens
Trigger: Calling canonicalize on a path containing a symlink cycle, e.g. `ln -s a a` or `ln -s b b; ln -s a b`, so the loop detection set contains a duplicate (file_info, path_to_follow) entry.
Common situations: Accidentally creating self-referential symlinks in scripts or build trees; recursive directory snapshots with relative symlinks pointing back up; copy operations (cp -r) into trees with cyclic links.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- mv-error-inter-device-move-failed
- mv-error-inter-device-move-failed (from, to, err)
- mv-error-permission-denied
- could not allocate a unique temp name in destination…
- Disabling rust signal handlers failed
AI-assisted analysis of uutils/coreutils@92995feca2 (2026-09-20).
Data as JSON: /api/errors/579b8d63168cb105.
Report an issue: GitHub.
Appendix: source
Thrown at src/uucore/src/lib/features/fs.rs:395
if res_mode == ResolveMode::None {
continue;
}
match resolve_symlink(&result) {
Ok(Some(link_path)) => {
for link_part in link_path.components().rev() {
parts.push_front(link_part.into());
}
if followed_symlinks < SYMLINKS_TO_LOOK_FOR_LOOPS {
followed_symlinks += 1;
} else {
let file_info =
FileInformation::from_path(result.parent().unwrap(), false).unwrap();
let mut path_to_follow = PathBuf::new();
for part in &parts {
path_to_follow.push(part.as_os_str());
}
if !visited_files.insert((file_info, path_to_follow)) {
return Err(Error::new(
ErrorKind::InvalidInput,
"Too many levels of symbolic links",
)); // TODO use ErrorKind::FilesystemLoop when stable
}
}
result.pop();
}
Err(e)
if (miss_mode == MissingHandling::Existing
|| (miss_mode == MissingHandling::Normal && !parts.is_empty())) =>
{
return Err(e);
}
_ => {}
}
}
// raise Not a directory if required
match miss_mode {View on GitHub (pinned to 92995feca2)