xai-org/grok-build · error

workspace is on '{current}', expected '{expected}'

Error message

workspace is on '{current}', expected '{expected}'

What it means

`ensure_on_branch` guards the sync-base flow: it reads the workspace's current branch via `git rev-parse --abbrev-ref HEAD` and, if an expected branch was supplied and the checked-out branch differs, aborts with this message. This prevents merging/syncing from the wrong base. The doc comment notes detached HEAD reports "HEAD" and so never matches an expected branch name.

Source

Thrown at crates/codegen/xai-grok-workspace/src/session/git.rs:2914

    if ok {
        return Ok((PushStatus::Ok, out));
    }
    let lower = out.to_lowercase();
    let status = if lower.contains("non-fast-forward") || lower.contains("fetch first") {
        PushStatus::Conflict
    } else {
        PushStatus::Failed
    };
    Ok((status, out))
}
/// Refuse unless the workspace is on exactly `expected`. Detached HEAD
/// reports "HEAD" and so never matches.
async fn ensure_on_branch(git_root: &Path, expected: Option<&str>) -> Result<()> {
    let Some(expected) = expected else {
        return Ok(());
    };
    let current = git_cli(git_root, &["rev-parse", "--abbrev-ref", "HEAD"]).await?;
    anyhow::ensure!(
        current == expected,
        "workspace is on '{current}', expected '{expected}'"
    );
    Ok(())
}
pub async fn commit(git_root: &Path, req: &GitCommitReq) -> Result<CommitResult> {
    let start = std::time::Instant::now();
    ensure_on_branch(git_root, req.expected_branch.as_deref()).await?;
    if req.seed_default_excludes {
        seed_default_excludes(git_root).await?;
    }
    if req.stage_all {
        git_cli_mut(git_root, &["add", "-A"]).await?;
    }
    let clean = req.stage_all
        && !req.amend
        && git_cli_raw(git_root, &["diff", "--cached", "--quiet"])
            .await?

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Run `git checkout <expected-branch>` in the workspace and retry
  2. If detached, `git switch -c <branch>` or `git checkout <expected>` first
  3. Call the API without `expected_branch` if branch enforcement is not desired (it becomes a no-op check)
  4. Compare `git rev-parse --abbrev-ref HEAD` with the expected branch before invoking

Example fix

// before
sync_base(&git_root, req) // workspace on 'feature'
// after
git_cli(&git_root, &["checkout", "main"]).await?;
sync_base(&git_root, req)
Defensive patterns

Strategy: validation

Validate before calling

let cur = String::from_utf8(Command::new("git").args(["rev-parse","--abbrev-ref","HEAD"]).current_dir(git_root).output()?.stdout)?.trim().to_string();
if let Some(expected) = expected_branch {
    if cur != expected { return Err(format!("on {cur}, expected {expected}; checkout first")); }
}

Prevention

When it happens

Trigger: Calling sync-base with `expected_branch` while the workspace is checked out on a different branch, or in detached-HEAD state (then `current` is the literal "HEAD").

Common situations: Agent or user left the workspace on a feature branch; a previous operation checked out a commit leaving detached HEAD; expected branch was renamed on the remote.

Related errors


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