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
- Run `gh auth status` and ensure gh is authenticated with repo scope.
- Check for an existing PR first: `gh pr list --head <branch> --json url` and skip creation if one exists.
- Confirm the base branch exists on the remote (`git ls-remote origin <base>`).
- 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
- Run `gh auth login` (with repo scope) before any PR creation flow.
- In CI, set `GH_TOKEN`/`GITHUB_TOKEN` so gh is non-interactive.
- Check `gh pr list --head <branch>` first to avoid duplicate-create errors.
- Validate label and reviewer names against the repo before passing them in DraftPrOptions.
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
- PR title cannot be empty
- git push failed: {stderr}
- Unable to infer ECC repo root from install-state operations
- --no-browser is valid only for ecc ito login; auth is valida
- ${command} ${args.join(' ')} failed: ${(result.stderr || res
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/3ba5929fc0db4570.
Report an issue: GitHub.