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

Unable to determine installed skill directory after clone (n

Error message

Unable to determine installed skill directory after clone (no new directory found)

What it means

install_git_skill_source snapshots the skills directory, runs 'git clone --depth 1 <source>' inside it, then detect_newly_installed_directory diffs before/after to locate the installed directory. Zero new directories means git reported success but nothing new appeared — most often because git cloned into a pre-existing empty directory that was already in the snapshot (git permits cloning into an existing empty dir).

Source

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

    Ok(paths)
}

fn detect_newly_installed_directory(
    skills_path: &Path,
    before: &HashSet<PathBuf>,
) -> Result<PathBuf> {
    let mut created = Vec::new();
    for entry in std::fs::read_dir(skills_path)? {
        let entry = entry?;
        let path = entry.path();
        if !before.contains(&path) && path.is_dir() {
            created.push(path);
        }
    }

    match created.len() {
        1 => Ok(created.remove(0)),
        0 => anyhow::bail!(
            "Unable to determine installed skill directory after clone (no new directory found)"
        ),
        _ => anyhow::bail!(
            "Unable to determine installed skill directory after clone (multiple new directories found)"
        ),
    }
}

fn enforce_skill_security_audit(
    skill_path: &Path,
    allow_scripts: bool,
) -> Result<audit::SkillAuditReport> {
    let report = audit::audit_skill_directory_with_options(
        skill_path,
        audit::SkillAuditOptions { allow_scripts },
    )?;
    if report.is_clean() {
        return Ok(report);

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. List the workspace skills/ directory and remove any leftover empty directory named after the repo being cloned, then retry the install
  2. Run installs serially — never two skills install commands against the same workspace at once
  3. If it persists, run 'git clone --depth 1 <url>' manually inside the skills dir to see what layout git produces

Example fix

# before: empty leftover dir 'my-skill' makes the diff find nothing new
ls skills/            # my-skill/ (empty)

# after
rmdir skills/my-skill && zeroclaw skills install <git-url>
Defensive patterns

Strategy: retry

Validate before calling

// Before a git-source install, clear stale empty dirs named after the repo:
let repo_dir_name = source.trim_end_matches('/').rsplit('/').next()
    .unwrap_or_default().trim_end_matches(".git");
let candidate = skills_path.join(repo_dir_name);
if candidate.is_dir() && std::fs::read_dir(&candidate)?.next().is_none() {
    std::fs::remove_dir(&candidate)?;
}

Try / catch

match install_git_skill_source(url, &skills_path, allow_scripts) {
    Err(e) if e.to_string().contains("no new directory found") => {
        // clean leftover empty dirs in skills_path, then retry once
    }
    r => r,
}

Prevention

When it happens

Trigger: skills/<repo-name> already exists as an empty directory when the clone runs; the cloned directory is deleted concurrently between clone and scan; another process restructures the skills dir mid-install.

Common situations: A previous failed install left an empty directory behind; two installs racing in the same workspace; interrupted cleanup after an audit rejection removed the wrong residue.

Related errors


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