jdx/mise · error
a validated copy_link has a staged parent
Error message
a validated copy_link has a staged parent
What it means
When materializing a `copy_link`, the code takes `staged_link.parent().expect("a validated copy_link has a staged parent")`. Because `staged_link` is built as a joined path, parent() should always exist; None would mean `link` itself is an empty path or the staged root is empty, i.e. the validated link value degenerated.
Solutions
- Ensure the copy_link value is a non-empty relative path (e.g. "subdir/target" not "")
- Check the staged_source base is a valid non-empty directory before staging
- Replace the expect with an error carrying the link value for easier diagnosis
Example fix
// before copy_link = "" // after copy_link = "bin/shared-tool"
Defensive patterns
Strategy: validation
Validate before calling
if link.as_os_str().is_empty() {
return Err(anyhow!("copy_link path must be non-empty"));
} Type guard
fn is_valid_link(link: &Path) -> bool {
!link.as_os_str().is_empty() && link.is_relative()
} Prevention
- Validate copy_link entries when parsing remote config
- Reject empty or whitespace-only link paths early
- Ensure the staged base directory is non-empty and exists
When it happens
Trigger: Applying a copy_link (src/system/remote.rs:881) where the `link` relative path is empty or the staged_source base is empty, making `staged_link` a bare root with no parent.
Common situations: A copy_link config entry with an empty or whitespace path; templated link path expanding to empty; base path left unset when joining.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- a provided source resolves to a path
- bootstrap_command returned an unsafe mise path
- cannot track through symlinked parent ; explicitly track…
- incompatibility was identified
- returned an unsafe absolute path
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/85e0913ed5d935ee.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/remote.rs:881
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()))?;
let source_link = source.join(link);
let staged_link = staged_source.join(link);
let target = fs::canonicalize(&source_link)
.wrap_err_with(|| format!("failed to resolve copy_link {}", link.display()))?;
let parent = staged_link
.parent()
.expect("a validated copy_link has a staged parent");
let original_permissions = make_directory_writable(parent)?;
let result = (|| {
crate::file::remove_file(&staged_link)?;
if target.is_dir() {
fs::create_dir(&staged_link)?;
crate::file::copy_dir_all_preserve_symlinks(&target, &staged_link)?;
} else {
crate::file::copy(&target, &staged_link)?;
}
Ok(())
})();
if let Some(permissions) = original_permissions {
fs::set_permissions(parent, permissions).wrap_err_with(|| {
format!(
"failed to restore staged directory permissions: {}",
parent.display()
)
})?;View on GitHub (pinned to 533346cc37)