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
- Read the wrapped {error} for the specific worker's shutdown failure
- Ensure all in-flight turns complete or are interrupted before shutdown so workers exit normally
- Check engine worker task logs for panics or aborts during teardown
- 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
- Drain all in-flight ops/turns before shutdown
- Avoid cancelling engine worker tasks mid-turn
- Log worker completion errors at their source so the shutdown error is not the first signal
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
- engine event channel closed before turn
- Failed to start turn: engine operation channel closed
- Failed to sync thread session
- Failed to trigger compaction: engine operation channel…
- Runtime terminal receipt monitor failed
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)