xai-org/grok-build · error · anyhow::Error

bare repository has no working directory

Error message

bare repository has no working directory

What it means

find_worktree_root discovers a git repository at `path` with gix and then requires a working directory. Bare repositories (created with `git init --bare` or clones ending in `.git` with no checkout) have `workdir() == None`, so the function cannot return a worktree root and throws this error.

Source

Thrown at crates/codegen/xai-fast-worktree/src/git/discovery.rs:59

            worktree_path.display()
        )
    }
}

/// Find the worktree root (working directory root) for a path.
///
/// This handles both regular repositories and worktrees correctly.
/// For a regular repo at `/repo`, returns `/repo`.
/// For a worktree at `/worktrees/wt1`, returns `/worktrees/wt1`.
/// For a subdirectory `/repo/subdir`, returns `/repo`.
pub(crate) fn find_worktree_root(path: &Path) -> Result<PathBuf> {
    let repo = gix::discover(path)
        .with_context(|| format!("failed to discover git repo at {}", path.display()))?;

    // workdir() returns the working directory root for both repos and worktrees
    let work_dir = repo
        .workdir()
        .ok_or_else(|| anyhow::anyhow!("bare repository has no working directory"))?;

    Ok(work_dir.to_path_buf())
}

/// Get the HEAD commit hash using gix.
pub(crate) fn get_head_commit(path: &Path) -> Result<String> {
    let repo = gix::discover(path)
        .with_context(|| format!("failed to discover git repo at {}", path.display()))?;

    let head = repo
        .head()
        .context("failed to get HEAD")?
        .peel_to_commit()
        .context("failed to peel HEAD to commit")?;

    Ok(head.id().to_string())
}

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Pass the path of a non-bare checkout (the directory containing a working tree) instead of the bare repo
  2. Clone the repository non-bare (`git clone <url>`) and operate on the clone
  3. If you intentionally need a working area from a bare repo, use `git worktree add` against it and pass the new worktree path

Example fix

// before
let root = find_worktree_root(Path::new("/srv/repo.git"))?;
// after
let root = find_worktree_root(Path::new("/srv/checkout"))?; // non-bare clone
Defensive patterns

Strategy: validation

Validate before calling

fn has_workdir(path: &Path) -> bool {
    gix::discover(path).map(|r| r.workdir().is_some()).unwrap_or(false)
}
// before: assert repo_path is a non-bare checkout
git::discover_guard(&repo_path)?;

Type guard

fn non_bare_repo(path: &Path) -> Option<std::path::PathBuf> {
    gix::discover(path).ok()?.workdir().map(|p| p.to_path_buf())
}

Try / catch

match find_worktree_root(path) {
    Ok(root) => root,
    Err(e) if e.to_string().contains("bare repository") => {
        return Err(anyhow!("{} is a bare repo; pass a checkout instead", path.display()))
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling find_worktree_root (or any API built on it) with a path pointing to a bare repository — e.g. a central server-side repo, a `.git` directory passed directly, or `--bare` clones.

Common situations: Pointing tooling at a remote/origin bare repo on a server or NAS; passing a repo's internal `.git` directory instead of the checkout root; CI setups that use bare clones for caching.

Related errors


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