{"record":{"id":"58b42ba13a57f32d","repo":"Hmbown/CodeWhale","slug":"task-manager-is-shutting-down-admission-is-closed","errorCode":null,"errorMessage":"Task manager is shutting down; admission is closed","messagePattern":"Task manager is shutting down; admission is closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/task_manager.rs","lineNumber":1771,"sourceCode":"            tool_calls: Vec::new(),\n            timeline: vec![TaskTimelineEntry {\n                timestamp: Utc::now(),\n                kind: \"queued\".to_string(),\n                summary: \"Task queued\".to_string(),\n                detail_path: None,\n            }],\n        };\n\n        self.admit_task_record(task, false).await\n    }\n\n    async fn admit_task_record(&self, task: TaskRecord, recover_stage: bool) -> Result<TaskRecord> {\n        {\n            let mut state = self.state.lock().await;\n            let _transaction = self.lock_store().await?;\n            self.refresh_locked(&mut state)?;\n            if self.cancel_token.is_cancelled() {\n                bail!(\"Task manager is shutting down; admission is closed\");\n            }\n            if task.execution_scope.as_deref() != Some(self.execution_scope()) {\n                bail!(\n                    \"Task execution scope is unverified or belongs to another Runtime; refusing adoption\"\n                );\n            }\n            let task_path = self.tasks_dir.join(format!(\"{}.json\", task.id));\n            // The staged extension is intentionally not `.json`, so startup\n            // replay ignores an interrupted create until the queue write has\n            // succeeded and this file is atomically promoted.\n            let staged_task_path = self.tasks_dir.join(format!(\".{}.json.pending\", task.id));\n            if recover_stage {\n                if let Some(accepted) = self.read_bound_task(&task.id)? {\n                    validate_bound_task_request(&accepted, &NewTaskRequest::from_task(&task))?;\n                    return Ok(accepted);\n                }\n                let current = read_bound_task_file(&staged_task_path, &task.id)?\n                    .context(\"Unaccepted task stage disappeared during recovery\")?;","sourceCodeStart":1753,"sourceCodeEnd":1789,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/task_manager.rs#L1753-L1789","documentation":"admit_task_record takes the state lock and a cross-process store transaction, then checks the shutdown cancel token. If the task manager is shutting down, admission is closed: no new (or recovered) task records may be added, because no worker will claim them. This fails loud instead of queueing a task that would never run.","triggerScenarios":"Calling add_task_with_id / admit_task_record (or the staged-recovery path that calls it) after task manager shutdown has begun (cancel_token cancelled) — e.g. a task submitted during app exit or while the Runtime is being torn down.","commonSituations":"A UI/automation race where a user clicks 'run' while the app is quitting; scheduled automation firing during shutdown; recovery replay racing process termination.","solutions":["Check the manager's shutdown state (or hold a shutdown broadcast/shutdown_requires flag) before submitting tasks","Re-submit the task after restart, or persist the intent externally and replay on next startup","Ensure automation schedulers are stopped before initiating task-manager shutdown","Handle the error in callers by surfacing 'app is shutting down' rather than retrying immediately"],"exampleFix":"// before\nmgr.add_task_with_id(req, id).await?;\n// after\nif mgr.is_shutdown().await {\n    persist_pending_submission(&req).await?; // replay on next startup\n} else {\n    mgr.add_task_with_id(req, id).await?;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match mgr.add_task_with_id(req, id).await { Err(e) if e.to_string().contains(\"shutting down\") => defer_submission_until_restart(req), r => r?, }","preventionTips":["Stop automation schedulers before initiating shutdown","Gate submissions on a shutdown flag/broadcast from the manager","Persist deferred submissions durably and replay after restart"],"tags":["rust","tasks","shutdown","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}