{"record":{"id":"83617f8a6dcb6805","repo":"xai-org/grok-build","slug":"merge-into-target-branch-succeeded-but-push-fa","errorCode":null,"errorMessage":"merge into '{target_branch}' succeeded but push failed ({status:?}): {}","messagePattern":"merge into '(.+?)' succeeded but push failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-workspace/src/session/git.rs","lineNumber":3330,"sourceCode":"    }\n    let _ = checkout_branch(git_root, conv_branch, false).await;\n    anyhow::bail!(\n        \"merge of '{conv_branch}' into '{target_branch}' failed: {}\",\n        scrub_git_output(&merge_out)\n    )\n}\n/// Push the merged target to origin when `push` is set, failing loudly (never\n/// forcing) so publish never records a deploy against an unpushed target.\nasync fn push_merged_target_if_requested(\n    git_root: &Path,\n    target_branch: &str,\n    push: bool,\n) -> Result<()> {\n    if !push {\n        return Ok(());\n    }\n    let (status, out) = push_classified(git_root).await?;\n    anyhow::ensure!(\n        status == PushStatus::Ok,\n        \"merge into '{target_branch}' succeeded but push failed ({status:?}): {}\",\n        scrub_git_output(&out)\n    );\n    Ok(())\n}\n/// `Push` (`workspace.git_push`): push a branch (or current `HEAD`) to `origin`,\n/// classifying the outcome. Never forces. Output is credential-scrubbed.\npub async fn push_branch(git_root: &Path, branch: Option<&str>) -> Result<GitPushResult> {\n    let refspec = branch.unwrap_or(\"HEAD\");\n    if let Some(branch) = branch {\n        ensure_ref_arg_safe(branch, \"branch\")?;\n    }\n    let (ok, out) = git_cli_raw_mut(\n        git_root,\n        &[\"push\", \"-u\", \"origin\", \"--end-of-options\", refspec],\n    )\n    .await?;","sourceCodeStart":3312,"sourceCodeEnd":3348,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/session/git.rs#L3312-L3348","documentation":"After a successful merge into the target branch, the flow optionally pushes to origin. If the push step exits with a non-Ok classification (network/auth/rejected non-fast-forward etc.), the library raises this error noting the merge itself succeeded but the push failed, with scrubbed push output for diagnostics.","triggerScenarios":"Running merge-to-target with push=true (crates/codegen/xai-grok-workspace/src/session/git.rs:3330) when `git push` fails: remote rejected the update (diverged/non-fast-forward), missing or expired credentials, no write permission, offline, or push protected-branch rules.","commonSituations":"Origin moved ahead while the session ran (someone else pushed to main); CI machine has no git credentials or an expired token; branch protection on the remote blocks direct pushes; corporate proxy/firewall blocks the remote.","solutions":["Fetch and inspect the remote: if it diverged, rebase/merge onto the updated target branch locally, then push again.","Fix credentials (git credential helper, refreshed token, SSH key) and verify `git push` manually.","If the local tree already holds the merge, a simple retry after resolving the remote state is safe — the merge itself succeeded.","Check remote branch-protection rules or use a PR-based flow if direct pushes to the target branch are blocked."],"exampleFix":"// before\ngit_ops.merge_to_main(&root, \"session/abc\", \"main\", true).await?; // fails when origin moved\n// after\nmatch git_ops.merge_to_main(&root, \"session/abc\", \"main\", true).await {\n    Ok(_) => {},\n    Err(e) if e.to_string().contains(\"push failed\") => {\n        // merge committed locally; reconcile with origin then re-push\n        run_git(&root, &[\"pull\", \"--rebase\"])?;\n        run_git(&root, &[\"push\"])?;\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"retry","validationCode":"// preflight: check remote connectivity and auth\nCommand::new(\"git\").args([\"ls-remote\", \"origin\", \"-h\", \"refs/heads/main\"]).status()?;","typeGuard":null,"tryCatchPattern":"// push failures after a successful merge are often transient or need rebase\nif let Err(e) = op().await {\n    if e.to_string().contains(\"push failed\") {\n        reconcile_with_origin()?; // fetch + rebase/merge onto updated target\n        retry_once(op).await?;\n    } else { return Err(e); }\n}","preventionTips":["Fetch origin and check the target branch hasn't moved before merging.","Ensure credentials (token/SSH key) are valid and refreshed in CI environments.","Use PR-based flows when the target branch has protection rules.","Remember the merge already succeeded locally — recover the push instead of redoing work."],"tags":["git","push","network","remote"],"backgroundTag":"git-push-rejected","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}