{"record":{"id":"7ff901d7741b77ec","repo":"Hmbown/CodeWhale","slug":"turn-lifecycle-task-ended-before-acknowledgement","errorCode":null,"errorMessage":"Turn lifecycle task ended before acknowledgement","messagePattern":"Turn lifecycle task ended before acknowledgement","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_threads.rs","lineNumber":6178,"sourceCode":"                allow_shell,\n                trust_mode,\n                auto_approve,\n                policy.permission,\n                configured_sandbox_mode,\n            );\n            let _sender = permit.send(op);\n            touch_lru(&mut active.lru, thread_id);\n            self.spawn_claimed_turn_monitor(\n                turn.clone(),\n                Some(user_item),\n                engine.clone(),\n                ClaimedTurnKind::Message,\n            )\n        };\n\n        acceptance_rx\n            .await\n            .map_err(|_| anyhow!(\"Turn lifecycle task ended before acknowledgement\"))?\n            .map_err(anyhow::Error::msg)\n        })\n        .await\n    }\n\n    pub async fn interrupt_turn(&self, thread_id: &str, turn_id: &str) -> Result<TurnRecord> {\n        {\n            let mut active = self.active.lock().await;\n            let Some(active_thread) = active.engines.get_mut(thread_id) else {\n                bail!(\"Thread is not loaded\");\n            };\n            let Some(active_turn) = active_thread.active_turn.as_mut() else {\n                bail!(\"No active turn on thread {thread_id}\");\n            };\n            if active_turn.turn_id != turn_id {\n                bail!(\"Turn {turn_id} is not active on thread {thread_id}\");\n            }\n            active_turn.interrupt_requested = true;","sourceCodeStart":6160,"sourceCodeEnd":6196,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/runtime_threads.rs#L6160-L6196","documentation":"Sentinel from acceptance_rx.await.map_err in submit_turn: the oneshot/mpsc receiver failed because the spawned turn lifecycle task (the closure that claims the permit and sends Op to the engine) exited or was dropped before sending an acknowledgement. It signals the producer side died — engine loop panicked, task aborted, or the channel sender was dropped — not that the turn itself failed.","triggerScenarios":"Thrown at crates/tui/src/runtime_threads.rs:6178 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the TUI logs/engine task panic output to find why the lifecycle task exited before acking","Verify the engine operation channel and permit machinery are alive (engine not shut down mid-submit)","Resubmit the turn once the underlying task failure is diagnosed; the turn was never acknowledged so no durable turn record was accepted"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}