{"record":{"id":"3e924eef7408af28","repo":"affaan-m/ECC","slug":"git-push-failed-stderr","errorCode":null,"errorMessage":"git push failed: {stderr}","messagePattern":"git push failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":560,"sourceCode":"        anyhow::bail!(\"PR title cannot be empty\");\n    }\n\n    let base_branch = options\n        .base_branch\n        .as_deref()\n        .map(str::trim)\n        .filter(|value| !value.is_empty())\n        .unwrap_or(&worktree.base_branch);\n\n    let push = Command::new(\"git\")\n        .arg(\"-C\")\n        .arg(&worktree.path)\n        .args([\"push\", \"-u\", \"origin\", &worktree.branch])\n        .output()\n        .context(\"Failed to push worktree branch before PR creation\")?;\n    if !push.status.success() {\n        let stderr = String::from_utf8_lossy(&push.stderr);\n        anyhow::bail!(\"git push failed: {stderr}\");\n    }\n\n    let mut command = Command::new(gh_bin);\n    command\n        .arg(\"pr\")\n        .arg(\"create\")\n        .arg(\"--draft\")\n        .arg(\"--base\")\n        .arg(base_branch)\n        .arg(\"--head\")\n        .arg(&worktree.branch)\n        .arg(\"--title\")\n        .arg(title)\n        .arg(\"--body\")\n        .arg(body);\n    for label in options\n        .labels\n        .iter()","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L542-L578","documentation":"create_draft_pr_with_gh pushes the worktree branch with `git push -u origin <branch>` before invoking `gh pr create`. A non-zero push exit re-throws git's stderr. This happens before any GitHub API call, so auth/rate-limit issues are not yet in play.","triggerScenarios":"No network/offline; no `origin` remote or wrong push URL; branch already exists on the remote with divergent history and `push -u` is non-forcing; SSH key/credential helper missing or rejected; remote rejected by a pre-receive hook (branch protection, signed-commits policy).","commonSituations":"First push of a new feature branch over a flaky connection; SSH agent not running; branch was force-pushed by someone else; protected branch rules reject the push; corporate proxy blocks the git protocol.","solutions":["Confirm `origin` exists and is reachable: `git -C <path> remote -v` and a manual `git ls-remote origin`.","For divergent branch history, decide between rebase/merge or an explicit force-push (the library does not force-push; you must reconcile history first).","Ensure credentials are configured (SSH key loaded, or `gh auth setup-git` for HTTPS).","Retry once on transient network errors before surfacing the failure."],"exampleFix":"// before\nlet url = create_draft_pr(&worktree, title, body)?;\n\n// after\n// pre-flight: confirm origin is reachable\nlet ok = Command::new(\"git\").arg(\"-C\").arg(&worktree.path)\n    .args([\"ls-remote\", \"origin\", \"HEAD\"]).output()?.status.success();\nif !ok { anyhow::bail!(\"cannot reach origin; check network/auth\"); }\nlet url = create_draft_pr(&worktree, title, body)?;","handlingStrategy":"retry","validationCode":"use std::process::Command;\n\nfn origin_reachable(worktree: &WorktreeInfo) -> bool {\n    Command::new(\"git\")\n        .arg(\"-C\").arg(&worktree.path)\n        .args([\"ls-remote\", \"origin\", \"HEAD\"])\n        .output()\n        .map(|o| o.status.success())\n        .unwrap_or(false)\n}\n\nif !origin_reachable(&worktree) {\n    anyhow::bail!(\"origin is not reachable; check network and credentials\");\n}\nlet url = create_draft_pr(&worktree, title, body)?;","typeGuard":null,"tryCatchPattern":"fn create_pr_with_retry(w: &WorktreeInfo, title: &str, body: &str, attempts: u8) -> anyhow::Result<String> {\n    let mut last = None;\n    for _ in 0..attempts {\n        match create_draft_pr(w, title, body) {\n            Ok(url) => return Ok(url),\n            Err(e) => {\n                let m = format!(\"{e:#}\");\n                if m.contains(\"git push failed\") && (m.contains(\"timed out\") || m.contains(\"Connection\")) {\n                    last = Some(e); // transient — retry\n                    continue;\n                }\n                return Err(e); // non-transient — surface\n            }\n        }\n    }\n    Err(last.unwrap())\n}","preventionTips":["Run `gh auth setup-git` once so HTTPS credentials are wired into git itself.","Confirm `git remote -v` shows the expected push URL before the first PR.","Rebase onto the latest remote base before pushing to avoid non-fast-forward rejections (the library does not force-push).","Retry transient network errors once before surfacing."],"tags":["git","subprocess","worktree","push","network","pull-request"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}