Hmbown/CodeWhale · error

Runtime engine shutdown failed

Error message

Runtime engine shutdown failed: {error}

What it means

During RuntimeThreadManager shutdown, after sending Op::Shutdown to every engine (main engines and workers), the manager awaits each retained worker completion via await_retained_completion. If any worker reports an error while finishing, the last error is recorded as 'Runtime engine shutdown failed'. This means an engine task failed to shut down cleanly, not that shutdown itself was refused.

Solutions

  1. Read the wrapped {error} for the specific worker's shutdown failure
  2. Ensure all in-flight turns complete or are interrupted before shutdown so workers exit normally
  3. Check engine worker task logs for panics or aborts during teardown
  4. Retain the error from shutdown and handle it at the caller instead of ignoring the Result

Example fix

// before
manager.shutdown().await.expect("shutdown");
// after
if let Err(e) = manager.shutdown().await {
    tracing::error!("engine workers failed to shut down: {e:#}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

let workers = manager.engine_workers.lock().clone();
let all_idle = workers.iter().all(|(_, w)| completion_finished(w));

Type guard

fn worker_is_idle(worker: &RuntimeCompletion) -> bool { completion_finished(worker) }

Try / catch

if let Err(e) = manager.shutdown().await {
    if e.to_string().contains("engine shutdown failed") {
        tracing::error!("a worker failed to shut down cleanly: {e:#}");
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling shutdown on RuntimeThreadManager while engine workers exist; sending Op::Shutdown succeeds on the channel but the worker's retained completion future resolves with Err, e.g. the worker panicked or its join/completion returned an error.

Common situations: Stopping the TUI runtime with background engine workers still processing ops; a worker that crashed mid-turn; resource exhaustion (task abort) during process teardown.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/9472aa9b0c8135c2. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/runtime_threads.rs:5217

                failure = Some(anyhow!("Runtime turn interruption failed: {error}"));
            }
        }
        let workers = self.engine_workers.lock().clone();
        for engine in engines
            .iter()
            .chain(workers.iter().map(|(engine, _)| engine))
        {
            engine.cancel_with_reason(crate::core::engine::CancelReason::Internal);
        }
        for engine in engines
            .iter()
            .chain(workers.iter().map(|(engine, _)| engine))
        {
            let _ = engine.send(Op::Shutdown).await;
        }
        for (_, worker) in workers {
            if let Err(error) = await_retained_completion(&worker).await {
                failure = Some(anyhow!("Runtime engine shutdown failed: {error}"));
            }
        }
        // Recovery reads can publish receipts too. Flushes that already passed
        // their admission check retain this mutex through all receipt writes;
        // later readers see the closed latch under the same mutex.
        {
            let _recovery = self.recovery_flush.lock().await;
        }
        loop {
            let monitors = self.turn_monitors.lock().clone();
            for monitor in monitors {
                if let Err(error) = await_retained_completion(&monitor).await {
                    failure = Some(anyhow!("Runtime terminal receipt monitor failed: {error}"));
                }
            }
            let mut monitors = self.turn_monitors.lock();
            monitors.retain(|monitor| !completion_finished(monitor));
            if monitors.is_empty() {

View on GitHub (pinned to 73e0f67d83)