xai-org/grok-build · error

agent runtime worker join: {e}

Error message

agent runtime worker join: {e}

What it means

The spawn_blocking task that builds the dedicated tokio current-thread runtime for the ACP agent worker was joined with a JoinError — the blocking task panicked or was cancelled before producing a runtime. spawn_agent_thread_direct maps that to this error so spawn fails cleanly instead of starting ACP in a broken state.

Source

Thrown at crates/codegen/xai-grok-pager/src/acp/spawn.rs:270

}

/// Spawn an agent in a dedicated thread with direct RPC dispatch.
///
/// The agent runs on a single-threaded tokio LocalSet runtime.
/// RPC requests go directly to the agent via Rc, bypassing simplex pipes.
async fn spawn_agent_thread_direct(
    spawn_agent: Box<dyn FnOnce(AcpClientTx) -> Result<Rc<MvpAgent>> + Send + 'static>,
    channel: AcpAgentChannel,
    cancel: CancellationToken,
    skills_paths: Vec<String>,
) -> Result<thread::JoinHandle<Result<()>>> {
    // Off the UI worker: failure must fail spawn, not start ACP.
    let rt = tokio::task::spawn_blocking(|| {
        let mut builder = tokio::runtime::Builder::new_current_thread();
        xai_tty_utils::runtime::build_with_blocking_pool(builder.enable_all())
    })
    .await
    .map_err(|e| anyhow::anyhow!("agent runtime worker join: {e}"))?
    .map_err(|e| {
        tracing::error!(error = %e, "failed to start agent runtime");
        anyhow::anyhow!("failed to start agent runtime: {e}")
    })?;
    Ok(thread::Builder::new()
        .name("acp-agent-worker".into())
        .spawn(move || -> Result<()> {
            let local = tokio::task::LocalSet::new();
            local.block_on(&rt, async move {
                let client_tx = channel.tx.clone();
                let agent_rc = spawn_agent(client_tx)?;

                // Direct dispatch: RPC requests go straight to the agent
                let gw_rx =
                    AcpGatewayReceiver::new(channel.rx, agent_rc.clone()).with_tracing(true);
                tokio::task::spawn_local(gw_rx.run());

                let _skills_watcher = {

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Inspect logs for a panic in the runtime-builder task (JoinError payload)
  2. Check thread/memory limits (ulimit -u, cgroup limits) that could kill worker threads
  3. Retry spawn; if it recurs during shutdown, avoid racing spawn_agent_thread_direct with process teardown
  4. Report/investigate build_with_blocking_pool panics in xai_tty_utils
Defensive patterns

Strategy: retry

Try / catch

match spawn_grok_shell(opts).await {
    Err(e) if e.to_string().contains("agent runtime worker join") => {
        // JoinError: panic or cancellation; check panic payload in logs, retry once
        retry_spawn(opts, 1).await
    }
    r => r,
}

Prevention

When it happens

Trigger: Calling spawn_agent_thread_direct (via spawn_grok_shell) when the spawn_blocking closure panics (e.g. build_with_blocking_pool fails/panics) or the blocking-pool task is cancelled.

Common situations: Runtime construction panicking under resource exhaustion (thread limits, memory), cancellation during shutdown racing spawn, bugs in blocking-pool configuration.

Related errors


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