uutils/coreutils · error · Error

Too many levels of symbolic links

Error message

Too many levels of symbolic links

What it means

The uucore `canonicalize` implementation resolves symlinks manually and tracks visited (file info, partial path) pairs. If the same target is encountered again, it concludes there is a symlink loop and returns `InvalidInput` with "Too many levels of symbolic links" (ErrorKind::FilesystemLoop is still unstable, hence the TODO).

Source

Thrown at src/uucore/src/lib/features/fs.rs:429

        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 85295bbf78)

Solutions

  1. Find and remove the looping symlink(s): `find -L . -type l` or `namei <path>`
  2. Recreate the symlink pointing to the correct target
  3. Use a filesystem loop detector before canonicalizing untrusted paths

Example fix

# before
ln -s ../b a; ln -s ../a b   # cycle
# after
ln -sfn /real/target a       # point at a real file/dir
Defensive patterns

Strategy: try-catch

Validate before calling

fn detects_loop(root: &Path, depth_limit: usize) -> bool {
    let mut seen = std::collections::HashSet::new();
    let mut cur = root.to_path_buf();
    for _ in 0..depth_limit {
        if cur.is_file() { return false; }
        if std::fs::read_link(&cur).is_ok() {
            let canon = std::fs::canonicalize(&cur);
            if canon.is_err() { return true; }
            if !seen.insert(canon.unwrap()) { return true; }
        }
        if !cur.pop() { break; }
    }
    false
}

Type guard

fn is_symlink_loop_err(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::InvalidInput
        && e.to_string().contains("Too many levels of symbolic links")
}

Try / catch

match uucore::fs::canonicalize(p) {
    Err(e) if is_symlink_loop_err(&e) => {
        eprintln!("symlink loop at {}", p.display());
        skip(p);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `canonicalize` on a path whose symlink chain forms a cycle, e.g. `ln -s a b; ln -s b a`, or a self-referencing directory symlink like `ln -s . loop`.

Common situations: Cyclic symlinks created by mistake in build trees, symlink farms with hand-made loops, restoring backups that re-created looped links.

Related errors


AI-assisted analysis of uutils/coreutils@85295bbf78 (2026-08-31). Data as JSON: /api/errors/579b8d63168cb105. Report an issue: GitHub.