{"record":{"id":"3ba5929fc0db4570","repo":"affaan-m/ECC","slug":"gh-pr-create-failed-stderr","errorCode":null,"errorMessage":"gh pr create failed: {stderr}","messagePattern":"gh pr create failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":598,"sourceCode":"        .filter(|value| !value.is_empty())\n    {\n        command.arg(\"--label\").arg(label);\n    }\n    for reviewer in options\n        .reviewers\n        .iter()\n        .map(|value| value.trim())\n        .filter(|value| !value.is_empty())\n    {\n        command.arg(\"--reviewer\").arg(reviewer);\n    }\n    let output = command\n        .current_dir(&worktree.path)\n        .output()\n        .context(\"Failed to create draft PR with gh\")?;\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        anyhow::bail!(\"gh pr create failed: {stderr}\");\n    }\n\n    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())\n}\n\nfn git_remote_origin_url(repo_root: &Path) -> Result<String> {\n    let output = Command::new(\"git\")\n        .arg(\"-C\")\n        .arg(repo_root)\n        .args([\"remote\", \"get-url\", \"origin\"])\n        .output()\n        .context(\"Failed to resolve git origin remote\")?;\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        anyhow::bail!(\"git remote get-url origin failed: {stderr}\");\n    }\n\n    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())","sourceCodeStart":580,"sourceCodeEnd":616,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L580-L616","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet url = create_draft_pr_with_options(&worktree, title, body, &opts)?;\n\n// after\n// pre-flight: gh auth must be ok\nlet authed = Command::new(\"gh\").args([\"auth\", \"status\"]).output()?.status.success();\nif !authed { anyhow::bail!(\"run `gh auth login` first\"); }\nlet url = create_draft_pr_with_options(&worktree, title, body, &opts)?;","handlingStrategy":"validation","validationCode":"use std::process::Command;\n\nfn gh_ready(worktree: &WorktreeInfo) -> bool {\n    let authed = Command::new(\"gh\").args([\"auth\", \"status\"]).output()\n        .map(|o| o.status.success()).unwrap_or(false);\n    if !authed { return false; }\n    // No existing PR for this head branch?\n    let existing = Command::new(\"gh\")\n        .args([\"pr\", \"list\", \"--head\", &worktree.branch, \"--state\", \"open\", \"--json\", \"url\"])\n        .current_dir(&worktree.path)\n        .output()\n        .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())\n        .unwrap_or_default();\n    existing == \"[]\"\n}\n\nif !gh_ready(&worktree) {\n    anyhow::bail!(\"gh not authenticated or a PR already exists for {}\", worktree.branch);\n}\nlet url = create_draft_pr_with_options(&worktree, title, body, &opts)?;","typeGuard":null,"tryCatchPattern":"match create_draft_pr_with_options(&worktree, title, body, &opts) {\n    Ok(url) => Ok(url),\n    Err(e) => {\n        let m = format!(\"{e:#}\");\n        if m.contains(\"already exists\") {\n            // parse and return the existing PR url from gh pr list\n        } else if m.contains(\"authentication\") || m.contains(\"not logged\") {\n            // prompt `gh auth login`\n        }\n        Err(e)\n    }\n}","preventionTips":["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."],"tags":["git","external-tool","github-cli","pull-request","auth"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}