xai-org/grok-build · warning
process scope already closed; fetch killed{}
Error message
process scope already closed; fetch killed{} What it means
FetchChild::spawn registers the spawned git fetch's process group with the global ProcessScope after starting the child. If the process scope has already been closed (global shutdown/teardown ran), registration fails; spawn immediately shuts the just-started fetch down (killing the process group) and throws this error, with a suffix (format_shutdown_suffix) reporting how the kill went. It signals 'the runtime is shutting down, this fetch never ran'.
Source
Thrown at crates/codegen/xai-grok-workspace/src/restore_fetch.rs:379
let _ = child.wait_timeout(FETCH_KILL_WAIT);
return Err(err).context("creating fetch process group");
}
};
if let Err(err) = group.attach_std(&child) {
let _ = child.kill();
let _ = child.wait_timeout(FETCH_KILL_WAIT);
return Err(err).context("attaching fetch to process group");
}
let group = Arc::new(group);
if !global_process_scope().register(&group) {
let mut spawned = Self {
child: Some(child),
group,
stderr: Some(stderr),
abandoned: false,
};
let shutdown = spawned.shutdown();
bail!(
"process scope already closed; fetch killed{}",
format_shutdown_suffix(shutdown.as_ref())
);
}
Ok(Self {
child: Some(child),
group,
stderr: Some(stderr),
abandoned: false,
})
}
fn wait_success(&mut self, timeout: Duration, spec: &str) -> Result<()> {
let child = self.child.as_mut().context("fetch child already reaped")?;
match child.wait_timeout(timeout) {
Ok(Some(status)) => {
self.child.take();
let stderr = self.take_stderr();View on GitHub (pinned to bc7f02eddd)
Solutions
- Stop retrying fetches once shutdown is signalled: check the shutdown/cancellation flag before invoking restore-fetch paths and exit the loop gracefully
- Treat this error as benign during shutdown — swallow/log it and let the interrupted operation be retried after restart
- Serialize teardown: ensure the process scope is only closed after all restore workers have joined, or guard fetch calls with the same lifetime as the scope
- Rerun the restore after restart; nothing was fetched (the child was killed immediately), so no partial state needs cleanup
Example fix
// before: one last fetch races scope shutdown
ensure_commits_reachable(repo, &head, &base)?;
// after: skip fetch work once the scope is closing
if process_scope_is_closed() {
tracing::info!("shutdown in progress; skipping restore fetch");
return Ok(EnsureCommitsOutcome::SkippedInvalidOid);
}
ensure_commits_reachable(repo, &head, &base)?; Defensive patterns
Strategy: try-catch
Validate before calling
fn can_start_fetch() -> bool {
!shutdown_requested() && process_scope_is_open()
}
// call before restore work: if (!can_start_fetch()) { log::info!("shutting down; skipping fetch"); return; } Try / catch
match ensure_commits_reachable(repo, &head, &base) {
Err(e) if e.to_string().starts_with("process scope already closed") => {
// shutdown raced the fetch; the child was killed and nothing was fetched
tracing::info!("restore fetch aborted by shutdown: {e:#}");
Ok(()) // benign during teardown; retry after restart
}
Err(e) => Err(e),
Ok(outcome) => Ok(outcome),
} Prevention
- Check the shutdown/cancellation flag before each fetch in restore loops and exit early
- Join all restore worker threads before closing the global ProcessScope so teardown never races in-flight fetches
- Make fetch attempts cancellable via a shared token checked between commits
- After this error, simply rerun the restore post-restart — the killed fetch leaves no partial state
When it happens
Trigger: Calling any restore-fetch path that spawns git fetch (directly or through run_with_deadline / idle_withheld_while_producer_in_flight-style flows) after the global process scope was closed: the process is shutting down, a Ctrl-C/shutdown hook fired between spawn and register, or a teardown path races a still-running restore that attempts one more fetch.
Common situations: User hits Ctrl-C while a restore is mid-flight and the operation attempts one final fetch; process exit handlers/teardown (kill_all) run concurrently with a lingering restore task; long-running daemons closing the scope during graceful shutdown while worker threads still call fetch.
Related errors
- git reset --hard {} failed: {}
- git clean {} failed: {}
- git checkout {} failed: {}
- git {shown} failed in {}: {}
- no .git file or directory found at {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/ea14ae4619c6f569.
Report an issue: GitHub.