{"record":{"id":"e007d58c1d7ebd78","repo":"Hmbown/CodeWhale","slug":"terminal-lane-transition-requires-a-terminal-statu","errorCode":null,"errorMessage":"terminal lane transition requires a terminal status","messagePattern":"terminal lane transition requires a terminal status","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/lane/src/registry.rs","lineNumber":378,"sourceCode":"    /// A pre-lock check is a TOCTOU: another process can transition the record\n    /// between the caller's read and this write, and the caller would then act\n    /// on a generation it never observed. Checking here means a stale fence\n    /// refuses without running `before_transition`, so no backend teardown\n    /// happens for a run the caller did not actually target.\n    ///\n    /// [`mark_terminal_if_active_with`]: Self::mark_terminal_if_active_with\n    pub fn mark_terminal_if_active_fenced<F>(\n        &self,\n        record: &mut LaneRecord,\n        status: LaneStatus,\n        expected_lifecycle_seq: Option<u64>,\n        before_transition: F,\n    ) -> Result<TerminalTransition>\n    where\n        F: FnOnce(&LaneRecord) -> Result<()>,\n    {\n        if status.is_active() {\n            bail!(\"terminal lane transition requires a terminal status\");\n        }\n\n        let lock_path = self.root.join(format!(\"{}.lock\", record.id));\n        let lock_file = OpenOptions::new()\n            .create(true)\n            .truncate(false)\n            .read(true)\n            .write(true)\n            .open(&lock_path)\n            .with_context(|| format!(\"open lane lock {}\", lock_path.display()))?;\n        let mut lock = fd_lock::RwLock::new(lock_file);\n        let _guard = lock\n            .write()\n            .with_context(|| format!(\"lock lane record {}\", record.id))?;\n\n        let mut current = self.load(&record.id)?;\n        // Fence first: a mismatched generation must not run backend teardown.\n        if let Some(expected) = expected_lifecycle_seq","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/lane/src/registry.rs#L360-L396","documentation":"This error is thrown by LaneRegistry::mark_terminal_if_active_fenced when a lane status that is still active is passed to a terminal-transition helper. The library only permits moving a lane into a terminal state (e.g. stopped/failed) when the transition target status is terminal; the fenced helper uses this to guarantee atomic, lock-protected terminal transitions.","triggerScenarios":"Calling mark_terminal_if_active_fenced (directly or via mark_terminal_if_active_with or stop) with a `status` argument for which `status.is_active()` returns true, e.g. passing Running/Active instead of a terminal status.","commonSituations":"Mapping an internal lane state enum to the terminal-status parameter in the wrong order; retry/stop logic that reuses an in-memory active status variable; refactorings that changed the status enum without updating stop paths.","solutions":["Pass a terminal status value (one for which `is_active()` is false) as the `status` argument.","Check the transition caller: if the lane should simply stop, use the `stop` entry point which derives the correct terminal status.","Inspect the lane record's current status first with the registry read APIs and only request a terminal transition when appropriate.","Update status-mapping code after enum changes so terminal values are no longer confused with active ones."],"exampleFix":"// before\nregistry.mark_terminal_if_active_fenced(record_id, LaneStatus::Running, |record| { /* ... */ })?;\n// after\nregistry.mark_terminal_if_active_fenced(record_id, LaneStatus::Stopped, |record| { /* ... */ })?;","handlingStrategy":"validation","validationCode":"if status.is_active() { panic!(\"terminal transition requires a terminal status, got {:?}\", status); }","typeGuard":"fn is_terminal(status: &LaneStatus) -> bool { !status.is_active() }","tryCatchPattern":null,"preventionTips":["Only call mark_terminal_if_active_* with enum variants known to be terminal.","Wrap terminal transitions in a helper that takes the record and derives the terminal status itself.","Recheck status mapping after any LaneStatus enum change."],"tags":["state-machine","lane-registry","invalid-state-transition"],"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"}