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

  1. Fix the symlink cycle on disk (find it with `find -L dir -type l` or remove the offending link)
  2. Use the library's non-loop-following canonicalization or std::fs::canonicalize which reports ELOOP natively
  3. 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

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


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)