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

not a git repository: {}

Error message

not a git repository: {}

What it means

In git_gate's root-discovery path (spawn_blocking around discover_git_root), a NotARepo result bails with 'not a git repository: <path>'. This gate runs before operations are allowed, refusing to proceed when the probe path has no git repository ancestor.

Source

Thrown at crates/codegen/xai-grok-workspace/src/session/git_gate.rs:645

fn forget_cached_roots(root: &Path) {
    ROOT_CACHE.lock().retain(|_, entry| entry.root != root);
}

async fn canonical_git_root(path: &Path) -> Result<PathBuf> {
    let cwd = dunce::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
    if let Some(root) = lookup_cached_root(&cwd) {
        return Ok(root);
    }

    let probe = cwd.clone();
    let discovered = tokio::task::spawn_blocking(move || discover_git_root(&probe))
        .await
        .map_err(|error| anyhow!("git discover task failed: {error}"))?;
    let discovered = match discovered {
        GitDiscoveryResult::Found(root) => root,
        GitDiscoveryResult::NotARepo => {
            anyhow::bail!("not a git repository: {}", path.display())
        }
        GitDiscoveryResult::DiscoveryFailed(error) => {
            return Err(error).context(format!("git discover failed for {}", path.display()));
        }
    };
    let root = dunce::canonicalize(&discovered).unwrap_or(discovered);
    store_cached_root(cwd, root.clone());
    Ok(root)
}

#[cfg(test)]
#[path = "git_gate_tests.rs"]
mod tests;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. cd into (or configure the workspace to point at) a directory inside a git repository
  2. Verify with `git rev-parse --show-toplevel` from the intended directory
  3. Re-clone or restore the repo if .git is missing
  4. Note the DiscoveryFailed arm instead wraps errors with 'git discover failed for <path>' context — this bail is specifically NotARepo

Example fix

// before
gate.check(Path::new("/tmp/scratch")).await?;
// after
gate.check(Path::new("/home/dev/project")).await?; // path inside the repo
Defensive patterns

Strategy: validation

Validate before calling

fn gate_precheck(cwd: &Path) -> anyhow::Result<()> {
    let out = std::process::Command::new("git").arg("-C").arg(cwd).args(["rev-parse","--show-toplevel"]).output()?;
    if !out.status.success() { anyhow::bail!("launch from inside a git repository, not {}", cwd.display()); }
    Ok(())
}

Type guard

fn has_git_ancestor(p: &Path) -> bool { p.ancestors().any(|a| a.join(".git").exists()) }

Try / catch

match gate.enter(cwd).await {
    Err(e) if e.to_string().starts_with("not a git repository") => {
        eprintln!("switch to your project directory or set workspace path inside the repo");
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: Invoking a gated session/workspace operation with a working directory outside any repo; the gate's probe walk reaches the filesystem root without finding .git.

Common situations: Running the tool from a scratch/temp directory; .git deleted or repo moved; passing a drive root or home dir as workspace; wrong cwd set by an IDE/runner.

Related errors


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