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

  1. Read merge_out in the message for the concrete git error and fix that (e.g. remove stale .git/index.lock)
  2. Verify the base ref is valid and shares history or pass --allow-unrelated-histories semantics via config the library exposes
  3. Ensure no other git process is running in the worktree
  4. 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

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


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/df755c2943fa7775. Report an issue: GitHub.