xai-org/grok-build · error
git discover task failed: {error}
Error message
git discover task failed: {error} What it means
Git root discovery runs in a blocking task (spawn_blocking(discover_git_root)). If the tokio runtime shuts down or the task is cancelled, .await returns a JoinError, which the library wraps as "git discover task failed: {error}". This is distinct from discovery itself failing — the discovery task never delivered a result.
Source
Thrown at crates/codegen/xai-grok-workspace/src/session/git_gate.rs:641
cached_at: Instant::now(),
},
);
}
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
- Retry the operation on a healthy runtime — discovery is idempotent.
- Ensure the tokio runtime outlives all in-flight calls (keep the Runtime/Arc of the service alive until shutdown completes, await your tasks before dropping the runtime).
- If JoinError shows a panic, fix the panicking path in discover_git_root / guard against poisoned state.
- In tests, use a common runtime handle per test and shutdown_timeout so tasks are not cancelled mid-flight.
Example fix
// before
{
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(service.discover(&path))?;
} // runtime dropped while other tasks still run -> JoinError
// after
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(service.discover(&path))?;
rt.shutdown_timeout(Duration::from_secs(10)); // let in-flight tasks finish Defensive patterns
Strategy: retry
Try / catch
// JoinError means the task never finished — safe to retry on a live runtime
match discover().await {
Err(e) if e.to_string().contains("git discover task failed") => {
tokio::time::sleep(Duration::from_millis(200)).await;
discover().await
}
other => other,
} Prevention
- Keep the tokio runtime (and the service using it) alive until all in-flight operations complete.
- Call runtime.shutdown_timeout instead of dropping the runtime abruptly.
- In tests, share one runtime per test and await spawned tasks before teardown.
- Fix panics inside discover_git_root — they surface to callers as this JoinError wrapper.
When it happens
Trigger: Calling the discovery entry point (git_gate.rs:641) while the tokio runtime is shutting down (task cancelled during drop), the runtime's blocking pool is saturated/killed, or the spawned task panics — the JoinError is then wrapped into this anyhow error.
Common situations: A server stopping while in-flight requests still attempt git discovery; tests tearing down their runtime before futures complete; blocking-pool exhaustion causing cancellation/panic in the discover task; panic inside discover_git_root (e.g. poisoned lock or unwraps) surfacing as a JoinError.
Related errors
- agent runtime worker join: {e}
- failed to start agent runtime: {e}
- blocking pool pre-warm stalled after {started} of {n} thread
- git reset --hard {} failed: {}
- git clean {} failed: {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/e737e024a66f0087.
Report an issue: GitHub.