Hmbown/CodeWhale · error
Runtime turn interruption failed
Error message
Runtime turn interruption failed: {error} What it means
During RuntimeThreadManager shutdown, each active turn is interrupted via interrupt_turn. If that fails AND the persisted turn is still InProgress, the manager records 'Runtime turn interruption failed' as the shutdown failure it eventually returns. It only counts as a failure when the turn genuinely never left the InProgress state, so a benign interrupt error that still left a terminal turn record is ignored.
Solutions
- Inspect the wrapped {error} from interrupt_turn to find the root cause (engine channel, engine not installed, etc.)
- Ensure turns reach a terminal status before shutdown: await or cancel the in-flight turn first
- Verify the turn store is writable and load_turn can read the turn record
- Retry shutdown after the engine worker has drained; the error is recorded only while the turn is stuck InProgress
Example fix
// before
let _ = manager.shutdown().await; // swallows nothing; error surfaces here
// after
for (thread_id, turn_id) in manager.active_turns().await {
manager.interrupt_turn(&thread_id, &turn_id).await?;
}
manager.shutdown().await?; Defensive patterns
Strategy: try-catch
Validate before calling
let turn = manager.store.load_turn(&turn_id)?;
if turn.status == RuntimeTurnStatus::InProgress { /* shutdown will interrupt; prepare for possible failure */ } Type guard
fn turn_is_terminal(status: RuntimeTurnStatus) -> bool { status != RuntimeTurnStatus::InProgress } Try / catch
match manager.shutdown().await {
Err(e) if e.to_string().contains("interruption failed") => {
// turn stuck InProgress: inspect interrupt_turn error inside {error}
tracing::error!("turn interruption failed: {e:#}");
}
other => other?,
} Prevention
- Complete or interrupt in-flight turns before calling shutdown
- Persist a terminal turn status on every turn exit path
- Monitor store health so load_turn writes/reads do not fail during shutdown
When it happens
Trigger: Calling RuntimeThreadManager::shutdown while a turn is in flight and interrupt_turn (thread_id, turn_id) returns Err; additionally the store.load_turn check finds turn.status == RuntimeTurnStatus::InProgress, meaning the interrupt did not persist a terminal status.
Common situations: Shutting the runtime down while a model stream is still running; a wedged engine task that never responds to the interrupt; a storage error that prevents the turn record from being updated before shutdown.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- engine event channel closed before turn
- Runtime engine shutdown failed
- Runtime terminal receipt monitor failed
- Task worker shutdown failed
- Wait for the pet recorder write before closing.
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/c43005d3191ef3cf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/runtime_threads.rs:5199
.iter()
.filter_map(|(id, state)| {
state
.active_turn
.as_ref()
.map(|turn| (id.clone(), turn.turn_id.clone()))
})
.collect::<Vec<_>>(),
)
};
let mut failure = None;
for (thread_id, turn_id) in active_turns {
if let Err(error) = self.interrupt_turn(&thread_id, &turn_id).await
&& !self
.store
.load_turn(&turn_id)
.is_ok_and(|turn| turn.status != RuntimeTurnStatus::InProgress)
{
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}"));View on GitHub (pinned to 73e0f67d83)