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.

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.

Appendix: 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)