jdx/mise · error
copy_link cannot be nested below a symbolic link: {}
Error message
copy_link cannot be nested below a symbolic link: {} What it means
While validating a copy_link, mise walks each parent component of the link using symlink_metadata and rejects the link if any intermediate component is itself a symlink. Resolving through a symlinked directory would make the final location ambiguous and could escape the staged source, so it fails early.
Source
Thrown at src/system/remote.rs:854
component,
Component::ParentDir | Component::RootDir | Component::Prefix(_)
)
})
{
bail!(
"copy_link must be a relative path within the source: {}",
link.display()
);
}
let mut parent = source.to_path_buf();
for component in link.parent().unwrap_or_else(|| Path::new("")).components() {
if let Component::Normal(component) = component {
parent.push(component);
let metadata = fs::symlink_metadata(&parent).wrap_err_with(|| {
format!("copy_link parent does not exist: {}", parent.display())
})?;
if metadata.file_type().is_symlink() {
bail!(
"copy_link cannot be nested below a symbolic link: {}",
link.display()
);
}
}
}
let path = source.join(link);
let metadata = fs::symlink_metadata(&path)
.wrap_err_with(|| format!("copy_link does not exist: {}", link.display()))?;
if !metadata.file_type().is_symlink() {
bail!("copy_link is not a symbolic link: {}", link.display());
}
Ok(())
}
fn materialize_link(source: &Path, staged_source: &Path, link: &Path) -> Result<()> {
validate_copy_link_path(staged_source, link)
.wrap_err_with(|| format!("staged copy_link is unsafe: {}", link.display()))?;View on GitHub (pinned to afd2eddd3a)
Solutions
- Point copy_link at a path whose parent directories are real directories
- Replace the intermediate symlink with a real directory (or copy its contents)
- Adjust the link to target the symlink's final destination directly
Example fix
// before copy_link = "bin/tool" // bin is a symlink // after copy_link = "scripts/bin/tool"
Defensive patterns
Strategy: validation
Validate before calling
function parentIsRealDir(root, rel) {
let cur = root;
for (const seg of path.posix.dirname(rel).split('/').filter(Boolean)) {
cur = path.join(cur, seg);
const st = fs.lstatSync(cur);
if (st.isSymbolicLink()) return false;
}
return true;
} Prevention
- Avoid symlinked intermediate directories inside staged sources
- Replace symlinked dirs with real directories before staging
- Add a CI check that lstat on each copy_link parent is not a symlink
When it happens
Trigger: The configured copy_link has a parent directory that is a symbolic link inside the staged source (e.g. link = "bin/tool" where bin is a symlink to ../scripts).
Common situations: Projects that restructure directories with symlinks (bin -> scripts/bin) then add copy_link entries; also generated layouts where CI creates symlinked folders before staging.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- copy_link must be a relative path within the source: {}
- copy_link is not a symbolic link: {}
- remote mise path does not name an executable: {command:?}
- relative remote mise path escapes the staged project: {comma
- relative remote mise path does not name an executable: {comm
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/c44fd92b0f210158.
Report an issue: GitHub.