affaan-m/ECC · error · anyhow::Error

git remote get-url origin failed: {stderr}

Error message

git remote get-url origin failed: {stderr}

What it means

git_remote_origin_url runs `git -C <repo_root> remote get-url origin`. A non-zero exit re-throws git's stderr. The function underpins github_compare_url and the GitHub-URL derivation logic; without an `origin` remote those features cannot work.

Source

Thrown at ecc2/src/worktree/mod.rs:613

        .context("Failed to create draft PR with gh")?;
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        anyhow::bail!("gh pr create failed: {stderr}");
    }

    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
}

fn git_remote_origin_url(repo_root: &Path) -> Result<String> {
    let output = Command::new("git")
        .arg("-C")
        .arg(repo_root)
        .args(["remote", "get-url", "origin"])
        .output()
        .context("Failed to resolve git origin remote")?;
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        anyhow::bail!("git remote get-url origin failed: {stderr}");
    }

    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
}

fn github_repo_web_url(origin: &str) -> Option<String> {
    let trimmed = origin.trim().trim_end_matches(".git");
    if trimmed.is_empty() {
        return None;
    }

    if let Some(rest) = trimmed.strip_prefix("git@") {
        let (host, path) = rest.split_once(':')?;
        return Some(format!("https://{host}/{}", path.trim_start_matches('/')));
    }

    if let Some(rest) = trimmed.strip_prefix("ssh://") {
        return parse_httpish_remote(rest);

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Add an origin remote: `git -C <root> remote add origin <url>`.
  2. If the remote is intentionally named differently, extend git_remote_origin_url or pass the remote name explicitly.
  3. Verify `repo_root` is the actual repository root with `git -C <root> rev-parse --show-toplevel`.
  4. Treat the `None`/Err path in callers (e.g. github_compare_url already returns Ok(None) when the URL is not GitHub-shaped) gracefully.

Example fix

// before
let origin = git_remote_origin_url(&repo_root)?;

// after
let origin = match git_remote_origin_url(&repo_root) {
    Ok(url) => url,
    Err(_) => {
        // no origin configured; degrade gracefully
        return Ok(None);
    }
};
Defensive patterns

Strategy: validation

Validate before calling

use std::process::Command;

fn origin_remote_url(repo_root: &Path) -> Option<String> {
    let out = Command::new("git")
        .arg("-C").arg(repo_root)
        .args(["remote", "get-url", "origin"])
        .output().ok()?;
    if out.status.success() {
        Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
    } else {
        None
    }
}

let origin = match origin_remote_url(&repo_root) {
    Some(u) => u,
    None => return Ok(None), // degrade gracefully when no origin is set
};

Try / catch

match git_remote_origin_url(&repo_root) {
    Ok(url) => Ok(Some(url)),
    Err(e) if format!("{e:#}").contains("No such remote") => Ok(None),
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling github_compare_url on a worktree whose repo root has no `origin` remote; the remote was renamed (e.g. to `upstream`); the repo root path passed in is not actually a git repo.

Common situations: Local-only repo cloned via file:// with no origin; remote renamed by a fork-and-repoint workflow; repo_root resolved incorrectly (pointed at a subdirectory that is itself a separate repo or no repo).

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/634f7869c5122f42. Report an issue: GitHub.