jdx/mise · error

copy_link must be a relative path within the source: {}

Error message

copy_link must be a relative path within the source: {}

What it means

validate_copy_link_path checks that the copy_link — a symlink to replicate in the staged remote source — is a strictly relative path inside the source. If the path contains ParentDir (..), RootDir (/) or a Windows Prefix component, mise rejects it because such links could escape the staged project boundary.

Source

Thrown at src/system/remote.rs:841

fn validate_copy_link(source: &Path, link: &Path) -> Result<()> {
    validate_copy_link_path(source, link)?;
    let path = source.join(link);
    fs::metadata(&path)
        .wrap_err_with(|| format!("copy_link target does not exist: {}", link.display()))?;
    Ok(())
}

fn validate_copy_link_path(source: &Path, link: &Path) -> Result<()> {
    if link.as_os_str().is_empty()
        || link.is_absolute()
        || link.components().any(|component| {
            matches!(
                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()
                );
            }
        }

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Change copy_link to a path relative to the source root without .. or leading /
  2. If the target lives outside the source, stage or vendor it into the project instead
  3. Verify the config value with a quick path sanity check before deploying

Example fix

// before
copy_link = "../../usr/bin/tool"
// after
copy_link = "bin/tool"
Defensive patterns

Strategy: validation

Validate before calling

function isSafeRelativeCopyLink(p) {
  const c = path.posix.parse(p);
  return !path.posix.isAbsolute(p) && !p.split('/').includes('..') && p !== '';
}

Type guard

const isValidCopyLink = (p) => typeof p === 'string' && !path.isAbsolute(p) && !p.split('/').some(s => s === '..' || s === '');

Prevention

When it happens

Trigger: Calling the remote staging path with a copy_link configured as an absolute path, a path starting with ../, or otherwise containing path components that traverse outside the source directory.

Common situations: Config mistakes where a user points copy_link at a shared toolchain outside the project (e.g. /usr/local/bin/x or ../../bin/x); also symlink configs copied from machines with different layouts.

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 jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/7b44af5429c11e96. Report an issue: GitHub.