{"record":{"id":"3fb2a7946259f549","repo":"Hmbown/CodeWhale","slug":"task-not-found-id","errorCode":null,"errorMessage":"Task not found: {id}","messagePattern":"Task not found: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/task_manager.rs","lineNumber":1480,"sourceCode":"        self.get_task_for_active_runtime(task_id).await?;\n        self.cancel_task(task_id).await\n    }\n\n    async fn cancel_task_visible_to(\n        &self,\n        id_or_prefix: &str,\n        owner_session_id: Option<&str>,\n    ) -> Result<TaskCancellation> {\n        let mut state = self.state.lock().await;\n        let id = resolve_task_id_visible_to(&state.tasks, id_or_prefix, owner_session_id)?;\n        let now = Utc::now();\n\n        let mut cancel_running = false;\n        let disposition = {\n            let task = state\n                .tasks\n                .get_mut(&id)\n                .ok_or_else(|| anyhow!(\"Task not found: {id}\"))?;\n            match task.status {\n                TaskStatus::Queued => {\n                    task.status = TaskStatus::Canceled;\n                    task.lifecycle_seq = task.lifecycle_seq.saturating_add(1);\n                    task.ended_at = Some(now);\n                    task.duration_ms = Some(0);\n                    push_timeline_entry(\n                        task,\n                        TaskTimelineEntry {\n                            timestamp: now,\n                            kind: \"canceled\".to_string(),\n                            summary: \"Task canceled before execution\".to_string(),\n                            detail_path: None,\n                        },\n                    );\n                    state.queue.retain(|queued_id| queued_id != &id);\n                    TaskCancelDisposition::Forced\n                }","sourceCodeStart":1462,"sourceCodeEnd":1498,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/task_manager.rs#L1462-L1498","documentation":"In the cancel path, resolve_task_id_visible_to already returned a full id computed from the same locked state.tasks map, and get_mut(&id) then failed. Because both lookups run under the same mutex on the same map, this branch is a defensive invariant guard, not an expected outcome: it would only fire if the resolver and the map disagreed (internal state corruption). Users should never see it under normal operation.","triggerScenarios":"Effectively unreachable through public APIs: it requires the task map to change between resolve_task_id_visible_to and get_mut while state is locked, e.g. memory corruption or a logic bug where the resolver returns an id not present in the map.","commonSituations":"If observed at all, it indicates a bug in TaskManager or corrupted persisted task state loaded at startup.","solutions":["Treat it as an internal invariant failure: capture logs and the persisted task state file.","Restart the session; if it reproduces, inspect the persisted tasks store for corruption.","Report it upstream with the cancel request's id_or_prefix and the task list."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let cancellation = match task_manager.cancel_task_visible_to(prefix, Some(session)).await {\n    Ok(c) => c,\n    Err(e) if e.to_string().contains(\"Task not found\") => {\n        // invariant guard: resolver just resolved this id under the same lock.\n        // Log and surface as an internal error; do not blind-retry.\n        tracing::error!(\"cancel invariant violation: {e:#}\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Log the exact id_or_prefix and a task-list snapshot if this ever fires — it indicates internal state corruption.","Keep persisted task state from being edited by hand; corrupted stores make invariant guards reachable."],"tags":["tasks","task-manager","invariant","cancel","not-found"],"backgroundTag":"entity-not-found","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}