nikivdev/code · error

Relative path must not contain '..'.

Error message

Relative path must not contain '..'.

What it means

normalize_relative_path walks the path's components and rejects any ParentDir component, i.e. any `..` segment. Parent-directory traversal would let a crafted path escape the project root and operate on arbitrary locations, so the function refuses it as a path-traversal defense rather than resolving it lexically.

Source

Thrown at src/code.rs:812

fn normalize_path(path: &str) -> Result<PathBuf> {
    let expanded = config::expand_path(path);
    let canonical = expanded.canonicalize().unwrap_or(expanded);
    Ok(canonical)
}

fn normalize_relative_path(path: &str) -> Result<PathBuf> {
    let trimmed = path.trim();
    if trimmed.is_empty() {
        bail!("Relative path cannot be empty.");
    }
    let rel = PathBuf::from(trimmed);
    if rel.is_absolute() {
        bail!("Relative path must not be absolute.");
    }
    for component in rel.components() {
        if matches!(component, std::path::Component::ParentDir) {
            bail!("Relative path must not contain '..'.");
        }
    }
    Ok(rel)
}

fn move_dir(from: &Path, to: &Path) -> Result<()> {
    match fs::rename(from, to) {
        Ok(()) => Ok(()),
        Err(err) => {
            if is_cross_device(&err) {
                copy_dir_all(from, to)?;
                fs::remove_dir_all(from)
                    .with_context(|| format!("failed to remove {}", from.display()))?;
                Ok(())
            } else {
                Err(err).with_context(|| {
                    format!("failed to move {} to {}", from.display(), to.display())
                })

View on GitHub (pinned to a747e741ae)

Solutions

  1. Rephrase the destination as a path strictly under the root with no `..`, e.g. `"projects/foo"`.
  2. If the target truly must be outside the root, use the absolute-path API/flag instead of the relative one, if available.
  3. Sanitize incoming user input: reject or strip `..` segments before passing the value through.
  4. Compute sibling/parent destinations at the call site rather than encoding them in the relative argument.

Example fix

// before
normalize_relative_path("../neighbor-project")
// after
normalize_relative_path("neighbor-project") // lives under the tool's project root
Defensive patterns

Strategy: validation

Validate before calling

let rel = Path::new(input.trim());
let has_parent = rel.components()
    .any(|c| matches!(c, std::path::Component::ParentDir));
if has_parent {
    return Err("path must not contain '..' segments".into());
}

Type guard

fn is_safe_relative(s: &str) -> bool {
    let p = Path::new(s.trim());
    p.is_relative() && !p.components().any(|c| matches!(c, std::path::Component::ParentDir))
}

Try / catch

match new_project(&rel) {
    Err(e) if e.to_string().contains("must not contain '..'") => {
        eprintln!("Place the project under the root; '..' traversal is not allowed.");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling new_project or migrate_project with a relative path containing `..`, e.g. `"../other-project"` or `"a/../../b"`.

Common situations: Users trying to place a project next to (rather than under) the root; scripts computing relative paths with `..`; untrusted input (web forms, generated configs) containing traversal sequences — deliberate or accidental.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/3fdc2b5554191b84. Report an issue: GitHub.