nikivdev/code · error

Relative path must not be absolute.

Error message

Relative path must not be absolute.

What it means

normalize_relative_path enforces that the supplied path is relative: it rejects any value starting with `/` (or a platform root/drive prefix) via rel.is_absolute(). The library joins the sanitized path onto its own project root, so an absolute path would escape the intended root and write outside the managed directory.

Source

Thrown at src/code.rs:808

    }

    Ok(())
}

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(())

View on GitHub (pinned to a747e741ae)

Solutions

  1. Pass only the folder name or a relative subpath, e.g. `"projects/foo"` instead of `/home/me/projects/foo`.
  2. Strip the known root prefix in your script: `rel="${abs#$ROOT/}"` before calling.
  3. Do not rely on `~` expansion — pass a relative name or expand it yourself and then convert to relative.
  4. Use Path::strip_prefix (or equivalent) to convert an absolute path to one relative to your base directory.

Example fix

// before
new_project("/home/alice/work/demo") // absolute → rejected
// after
new_project("work/demo") // relative to the tool's root
Defensive patterns

Strategy: validation

Validate before calling

let rel = input.trim();
if Path::new(rel).is_absolute() {
    return Err(format!("expected a relative path, got: {}", rel).into());
}

Type guard

fn is_relative_path(s: &str) -> bool { Path::new(s.trim()).is_relative() }

Try / catch

match new_project(&rel) {
    Err(e) if e.to_string().contains("Relative path must not be absolute") => {
        eprintln!("Pass a path relative to the tool's root, not an absolute one.");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling new_project or migrate_project with a relative-path argument like `/tmp/project`, `C:\dev\project`, or `~/project` (tilde is not expanded and, after expansion, would be absolute).

Common situations: Users pasting absolute paths from their file manager; scripts using `$HOME/...` where a relative name was expected; Windows drive-letter paths leaking into cross-platform scripts; unexpanded `~` assumptions.

Related errors


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