aaif-goose/goose · error

Failed to clone repo: {}

Error message

Failed to clone repo: {}

What it means

ensure_repo_cloned runs `gh repo clone <owner/repo> <dest>` when the destination has no .git directory (crates/goose-cli/src/recipes/github_recipe.rs:176-187). The first failure mode is the spawn itself returning an io::Error, which is mapped to this message with the repo name. Like [126], it means the gh process never ran — not that the clone failed.

Source

Thrown at crates/goose-cli/src/recipes/github_recipe.rs:181

fn ensure_repo_cloned(recipe_repo_full_name: &str) -> Result<PathBuf> {
    let local_repo_parent_path = env::temp_dir();
    if !local_repo_parent_path.exists() {
        std::fs::create_dir_all(local_repo_parent_path.clone())?;
    }
    let local_repo_path = get_local_repo_path(&local_repo_parent_path, recipe_repo_full_name)?;

    if local_repo_path.join(".git").exists() {
        Ok(local_repo_path)
    } else {
        let error_message: String = format!("Failed to clone repo: {}", recipe_repo_full_name);
        let status = Command::new("gh")
            .args(["repo", "clone", recipe_repo_full_name])
            .arg(&local_repo_path)
            .current_dir(local_repo_parent_path.clone())
            .set_no_window()
            .status()
            .map_err(|_: std::io::Error| anyhow::anyhow!(error_message.clone()))?;

        if status.success() {
            Ok(local_repo_path)
        } else {
            Err(anyhow::anyhow!(error_message))
        }
    }
}

fn fetch_origin(local_repo_path: &Path) -> Result<()> {
    let error_message: String = format!("Failed to fetch at {}", local_repo_path.to_str().unwrap());
    let status = git_command()
        .args(["fetch", "origin"])
        .current_dir(local_repo_path)
        .set_no_window()
        .status()
        .map_err(|_| anyhow::anyhow!(error_message.clone()))?;

View on GitHub (pinned to 3810898a74)

Solutions

  1. Verify gh resolves and runs in the exact execution context: `command -v gh && gh repo view owner/repo`
  2. If gh was never installed, install it (see [126]) — the auth check error would normally fire first, so a hit here suggests an environment change mid-run
  3. For sandboxed runners, allow exec of the gh binary in the sandbox profile
Defensive patterns

Strategy: validation

Validate before calling

# Ensure gh exists and can see the repo before invoking goose
command -v gh && gh repo view "$GOOSE_RECIPE_GITHUB_REPO" >/dev/null \
  && echo "clone preconditions OK"

Prevention

When it happens

Trigger: Command::new("gh").status() io failure at clone time: gh missing from PATH at this moment (it existed for the earlier auth check), exec format/permission error, or fork failure (EAGAIN) under resource pressure. Note this branch uses `gh`, not `git`.

Common situations: PATH mutated between goose startup and clone (shell wrapper, direnv hook), gh being upgraded/replaced concurrently, or a recipe run inside a container where gh is present but execution is denied by seccomp/AppArmor.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/1d1e214f84169dd7. Report an issue: GitHub.