{"record":{"id":"579b8d63168cb105","repo":"uutils/coreutils","slug":"too-many-levels-of-symbolic-links-579b8d","errorCode":null,"errorMessage":"Too many levels of symbolic links","messagePattern":"Too many levels of symbolic links","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/uucore/src/lib/features/fs.rs","lineNumber":395,"sourceCode":"        if res_mode == ResolveMode::None {\n            continue;\n        }\n        match resolve_symlink(&result) {\n            Ok(Some(link_path)) => {\n                for link_part in link_path.components().rev() {\n                    parts.push_front(link_part.into());\n                }\n                if followed_symlinks < SYMLINKS_TO_LOOK_FOR_LOOPS {\n                    followed_symlinks += 1;\n                } else {\n                    let file_info =\n                        FileInformation::from_path(result.parent().unwrap(), false).unwrap();\n                    let mut path_to_follow = PathBuf::new();\n                    for part in &parts {\n                        path_to_follow.push(part.as_os_str());\n                    }\n                    if !visited_files.insert((file_info, path_to_follow)) {\n                        return Err(Error::new(\n                            ErrorKind::InvalidInput,\n                            \"Too many levels of symbolic links\",\n                        )); // TODO use ErrorKind::FilesystemLoop when stable\n                    }\n                }\n                result.pop();\n            }\n            Err(e)\n                if (miss_mode == MissingHandling::Existing\n                    || (miss_mode == MissingHandling::Normal && !parts.is_empty())) =>\n            {\n                return Err(e);\n            }\n            _ => {}\n        }\n    }\n    // raise Not a directory if required\n    match miss_mode {","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/uutils/coreutils/blob/92995feca29e324a7c559ede91db81c32d9f5d59/src/uucore/src/lib/features/fs.rs#L377-L413","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nln -s loop loop; canonicalize(\"loop\")\n// after\nrm loop; ln -s /real/target loop","handlingStrategy":"try-catch","validationCode":"// detect cycles cheaply before canonicalizing\nfn has_symlink(p: &Path) -> bool { fs::symlink_metadata(p).map(|m| m.file_type().is_symlink()).unwrap_or(false) }","typeGuard":"fn is_canonicalizable(p: &Path) -> bool {\n    std::fs::read_link(p).is_err() || std::fs::canonicalize(p).is_ok()\n}","tryCatchPattern":"match canonicalize(path) {\n    Ok(p) => use(p),\n    Err(e) if e.to_string().contains(\"Too many levels of symbolic links\") => report_symlink_loop(path),\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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"],"tags":["filesystem","symlink","loop","unix"],"backgroundTag":"path-traversal-blocked","analyzedSha":"92995feca29e324a7c559ede91db81c32d9f5d59","analyzedAt":"2026-09-20T12:39:35.476Z","contentChangedAt":"2026-09-20T12:39:35.476Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}