affaan-m/ECC · error

gh pr create failed

Error message

gh pr create failed: {stderr}

What it means

create_draft_pr_with_gh runs `gh pr create` inside the worktree to open a draft pull request. When gh exits nonzero, the library bails with gh's stderr so the GitHub-side failure (GraphQL error, missing auth, invalid base, etc.) is visible in the message.

Solutions

  1. Read the stderr in the message — gh prints the exact GitHub API error.
  2. Run `gh auth status` in the worktree environment and authenticate (GH_TOKEN or `gh auth login`).
  3. Verify the base branch and any labels/reviewers exist on the remote before calling.
  4. Check for an existing open PR for the branch (`gh pr list --head <branch>`).
  5. Update the gh CLI if the error mentions an unknown flag.
Defensive patterns

Strategy: try-catch

Validate before calling

let auth = Command::new("gh").args(["auth", "status"]).output()?;
if !auth.status.success() { eprintln!("gh not authenticated"); }

Try / catch

match create_draft_pr(&wt, title, body) {
    Ok(url) => println!("draft PR: {url}"),
    Err(e) if e.to_string().contains("already exists") => eprintln!("PR already open"),
    Err(e) if e.to_string().contains("auth") => eprintln!("run: gh auth login or set GH_TOKEN"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling create_draft_pr when `gh` is unauthenticated, the base branch named in DraftPrOptions does not exist on the remote, the branch is already covered by an open PR, GitHub returns a validation error, or gh CLI is a version lacking a used flag.

Common situations: CI without `gh auth login` / GH_TOKEN set; typo'd custom base branch or nonexistent labels/reviewers passed in options; `draft PR already exists` after a retry; corporate proxy blocking api.github.com.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/3ba5929fc0db4570. Report an issue: GitHub.

Appendix: 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 8321021c54)