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

gh pr create failed: {stderr}

Error message

gh pr create failed: {stderr}

What it means

After a successful push, create_draft_pr_with_gh invokes `gh pr create --draft --base <base> --head <branch> --title ... --body ...` plus optional labels/reviewers. A non-zero exit re-throws gh's stderr. The push already succeeded, so the failure is specifically at the GitHub API/CLI layer.

Source

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

        .filter(|value| !value.is_empty())
    {
        command.arg("--label").arg(label);
    }
    for reviewer in options
        .reviewers
        .iter()
        .map(|value| value.trim())
        .filter(|value| !value.is_empty())
    {
        command.arg("--reviewer").arg(reviewer);
    }
    let output = command
        .current_dir(&worktree.path)
        .output()
        .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())

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Run `gh auth status` and ensure gh is authenticated with repo scope.
  2. Check for an existing PR first: `gh pr list --head <branch> --json url` and skip creation if one exists.
  3. Confirm the base branch exists on the remote (`git ls-remote origin <base>`).
  4. Validate label and reviewer names against the repo before passing them in DraftPrOptions.

Example fix

// before
let url = create_draft_pr_with_options(&worktree, title, body, &opts)?;

// after
// pre-flight: gh auth must be ok
let authed = Command::new("gh").args(["auth", "status"]).output()?.status.success();
if !authed { anyhow::bail!("run `gh auth login` first"); }
let url = create_draft_pr_with_options(&worktree, title, body, &opts)?;
Defensive patterns

Strategy: validation

Validate before calling

use std::process::Command;

fn gh_ready(worktree: &WorktreeInfo) -> bool {
    let authed = Command::new("gh").args(["auth", "status"]).output()
        .map(|o| o.status.success()).unwrap_or(false);
    if !authed { return false; }
    // No existing PR for this head branch?
    let existing = Command::new("gh")
        .args(["pr", "list", "--head", &worktree.branch, "--state", "open", "--json", "url"])
        .current_dir(&worktree.path)
        .output()
        .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
        .unwrap_or_default();
    existing == "[]"
}

if !gh_ready(&worktree) {
    anyhow::bail!("gh not authenticated or a PR already exists for {}", worktree.branch);
}
let url = create_draft_pr_with_options(&worktree, title, body, &opts)?;

Try / catch

match create_draft_pr_with_options(&worktree, title, body, &opts) {
    Ok(url) => Ok(url),
    Err(e) => {
        let m = format!("{e:#}");
        if m.contains("already exists") {
            // parse and return the existing PR url from gh pr list
        } else if m.contains("authentication") || m.contains("not logged") {
            // prompt `gh auth login`
        }
        Err(e)
    }
}

Prevention

When it happens

Trigger: gh is not authenticated (`gh auth login` not run); a PR already exists for the head branch; the base branch does not exist on the remote; the user lacks permission to create a PR in the repo; a label or reviewer name does not exist; gh API rate limit hit; gh binary is present but misconfigured.

Common situations: First-time use without `gh auth login`; CI runner with gh installed but no token; reviewer handle typo; branch protection preventing draft PRs; duplicated PR creation attempt.

Related errors


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