Hmbown/CodeWhale · error

git failed

Error message

git {} failed: {}

What it means

The git() helper wraps every git invocation for dispatch branch preparation and push. When git exits nonzero, it bails with the subcommand name and a sanitized version of stderr, so callers see a single, secret-free git failure message.

Solutions

  1. Read the sanitized stderr in the error to identify the underlying git failure
  2. Run the same git command manually to reproduce and fix (e.g. re-authenticate with gh auth login or a credential helper)
  3. Verify the repo path exists and is a valid git working tree
  4. Check network/VPN connectivity to the remote

Example fix

// before: push without credentials
// authentication failed
// after
gh auth login
# or
git config credential.helper store
Defensive patterns

Strategy: retry

Validate before calling

if !repo_path.join(".git").exists() { /* not a git repo; fix path first */ }
// and pre-check auth: git ls-remote <url> before long operations

Try / catch

match result {
    Err(e) if e.to_string().contains("git push failed") => {
        // check credentials/network, then retry with backoff
    }
    other => other?,
}

Prevention

When it happens

Trigger: Any git subcommand run through git() (clone, branch apply, push, ls-remote) exits nonzero — bad ref, auth failure, network error, dirty state, etc.

Common situations: Missing or expired credentials for the remote, no network access, invalid branch names, missing repository at repo path, or a git hook rejecting the operation.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/a40208f2d2e54b13. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/dispatch_runner.rs:574

fn remote_branch_exists(remote_url: &str, branch: &str) -> Result<bool> {
    let listing =
        git(None, &["ls-remote", "--heads", "--", remote_url, branch]).unwrap_or_default();
    Ok(listing
        .lines()
        .any(|line| line.contains(&format!("refs/heads/{branch}"))))
}

fn git(cwd: Option<&Path>, args: &[&str]) -> Result<String> {
    let mut command = Command::new("git");
    if let Some(cwd) = cwd {
        command.current_dir(cwd);
    }
    let output = command
        .args(args)
        .output()
        .context("failed to start git for the cloud agent branch")?;
    if !output.status.success() {
        bail!(
            "git {} failed: {}",
            args.first().unwrap_or(&""),
            sanitize_error(&String::from_utf8_lossy(&output.stderr))
        );
    }
    Ok(String::from_utf8_lossy(&output.stdout).to_string())
}

fn open_pr_github(
    slug: &str,
    job: &CloudJob,
    patch: &PatchReceipt,
    title: &str,
    body: &str,
) -> Result<String> {
    let body_dir = tempfile::tempdir().context("could not stage the PR body")?;
    let body_file = body_dir.path().join("body.md");
    std::fs::write(&body_file, body).context("could not write the PR body")?;

View on GitHub (pinned to 73e0f67d83)