zeroclaw-labs/zeroclaw · error · anyhow::Error

Source path does not exist: {source}

Error message

Source path does not exist: {source}

What it means

install_local_skill_source checks PathBuf::from(source).exists() before doing anything else and bails with the literal source string when the path is absent. The check runs before canonicalization, so relative paths resolve against the process's current working directory, and '~' is not expanded.

Source

Thrown at crates/zeroclaw-runtime/src/skills/mod.rs:2086

                    "failed to copy skill file from {} to {}",
                    src_path.display().to_string(),
                    dest_path.display()
                )
            })?;
        }
    }

    Ok(())
}

pub fn install_local_skill_source(
    source: &str,
    skills_path: &Path,
    allow_scripts: bool,
) -> Result<(PathBuf, usize)> {
    let source_path = PathBuf::from(source);
    if !source_path.exists() {
        anyhow::bail!("Source path does not exist: {source}");
    }

    let source_path = source_path
        .canonicalize()
        .with_context(|| format!("failed to canonicalize source path {source}"))?;
    let _ = enforce_skill_security_audit(&source_path, allow_scripts)?;

    let name = source_path
        .file_name()
        .context("Source path must include a directory name")?;
    let dest = skills_path.join(name);
    if dest.exists() {
        anyhow::bail!(
            "Destination skill already exists: {}",
            dest.display().to_string()
        );
    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Verify the path exists from the exact directory the process runs in
  2. Use an absolute path
  3. Expand ~ (or reject it) before passing the value to the installer

Example fix

# before
zeroclaw skills install ~/skills/my-skill   # tilde never expanded by the process

# after
zeroclaw skills install "$HOME/skills/my-skill"
Defensive patterns

Strategy: validation

Validate before calling

let p = shellexpand::tilde(source).into_owned(); // or expand manually
if !std::path::Path::new(&p).exists() {
    anyhow::bail!("skill source not found: {p}");
}
install_local_skill_source(&p, &skills_path, allow_scripts)?;

Type guard

fn skill_source_exists(source: &str) -> bool {
    std::path::Path::new(source).exists()
}

Prevention

When it happens

Trigger: Typo in the path; a relative path interpreted from a different cwd than the caller assumed; a path containing an unexpanded ~ (no shell expansion happens inside the process); the directory was moved or deleted.

Common situations: CLI or tool invoked with ~/skills/foo where nothing expanded the tilde; scripts that cd elsewhere before installing; paths copy-pasted from a different machine.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/0b3089ab1ba13cc8. Report an issue: GitHub.