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

  1. Stop retrying fetches once shutdown is signalled: check the shutdown/cancellation flag before invoking restore-fetch paths and exit the loop gracefully
  2. Treat this error as benign during shutdown — swallow/log it and let the interrupted operation be retried after restart
  3. 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
  4. 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

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


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