xai-org/grok-build · error · anyhow::Error
merge of base ref '{base}' failed: {merge_out}
Error message
merge of base ref '{base}' failed: {merge_out} What it means
In the base-sync merge flow, when `git merge` of the base ref finishes with neither clean success nor a conflict-marker outcome, the code bails with the merge command output. This means git itself failed (not a resolvable conflict) during syncing the base ref.
Source
Thrown at crates/codegen/xai-grok-workspace/src/session/git.rs:3077
let (merged, merge_out) =
git_cli_raw_mut(git_root, &["merge", "--no-edit", "FETCH_HEAD"]).await?;
if merged {
let sha = git_cli(git_root, &["rev-parse", "HEAD"]).await?;
return Ok(GitSyncBaseResult {
outcome: GitSyncBaseOutcome::Merged { sha },
});
}
if merge_in_progress(git_root).await? {
let files = git_cli(git_root, &["diff", "--name-only", "--diff-filter=U"])
.await?
.lines()
.map(str::to_owned)
.collect();
return Ok(GitSyncBaseResult {
outcome: GitSyncBaseOutcome::Conflicts { files },
});
}
anyhow::bail!("merge of base ref '{base}' failed: {merge_out}")
}
/// Reject a ref/branch value that could be parsed as a git option (leading `-`)
/// or that carries whitespace/control characters or `..`. A boundary guard for
/// client-influenced refs (notably `base_ref`) so they cannot be smuggled in as
/// flags; combined with `--end-of-options` at each call site.
fn ensure_ref_arg_safe(value: &str, what: &str) -> Result<()> {
anyhow::ensure!(!value.is_empty(), "{what} must not be empty");
anyhow::ensure!(
!value.starts_with('-'),
"{what} '{value}' must not start with '-'"
);
anyhow::ensure!(
!value.chars().any(|c| c.is_whitespace() || c.is_control()),
"{what} '{value}' contains whitespace or control characters"
);
anyhow::ensure!(
!value.contains(".."),
"{what} '{value}' must not contain '..'"View on GitHub (pinned to bc7f02eddd)
Solutions
- Read merge_out in the message for the concrete git error and fix that (e.g. remove stale .git/index.lock)
- Verify the base ref is valid and shares history or pass --allow-unrelated-histories semantics via config the library exposes
- Ensure no other git process is running in the worktree
- Abort any in-progress merge: `git merge --abort` then retry
Example fix
// before sync_base(git_root, base="origin/main").await?; // after rm -f .git/index.lock && git merge-base HEAD origin/main # verify related history, then retry
Defensive patterns
Strategy: try-catch
Validate before calling
let lock = git_root.join(".git/index.lock");
if lock.exists() { anyhow::bail!("stale index.lock present; remove before merging"); }
let _ = std::process::Command::new("git").arg("-C").arg(git_root).args(["merge-base","HEAD",base]).output()?; Type guard
fn merge_hard_failed(msg: &str) -> bool { msg.starts_with("merge of base ref") && !msg.contains("CONFLICT") } Try / catch
match sync_base(git_root, base).await {
Ok(r) => handle_outcome(r),
Err(e) if e.to_string().contains("merge of base ref") => {
let _ = git_cli(git_root, &["merge","--abort"]).await; // then fix per merge_out and retry
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Clear stale .git/index.lock after crashes before merging
- Ensure the base ref shares history with HEAD
- Serialize git operations per worktree to avoid contention
- Run git fsck if object corruption is suspected
When it happens
Trigger: git merge --ff/merge of base ref returns an unexpected exit code — e.g. unrelated histories with no merge strategy, ref locked, index locked, or corrupt object.
Common situations: Index.lock left by a crashed process; base ref naming an unrelated history; .git permissions issues; concurrent git processes in the same worktree.
Related errors
- merge of '{conv_branch}' into '{target_branch}' failed: {}
- git status failed: {}
- git worktree add failed: {}
- git fetch --no-tags origin {spec} failed ({status}): {stderr
- local '{target_branch}' has diverged from origin; resolve be
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/df755c2943fa7775.
Report an issue: GitHub.