{"record":{"id":"b4dfbfa2738f3c34","repo":"jdx/mise","slug":"an-operation-record-always-has-an-operation","errorCode":null,"errorMessage":"an operation record always has an operation","messagePattern":"an operation record always has an operation","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/scope.rs","lineNumber":508,"sourceCode":"                self.pending.checkpoint.tree.available = false;\n                self.pending.checkpoint.tree.reason = Some(format!(\"{err:#}\"));\n            }\n        }\n        if let Err(err) = self.write_pending() {\n            warn!(\"history: could not persist the operation record: {err:#}\");\n        }\n    }\n\n    fn kind(&self) -> OperationKind {\n        self.operation().kind\n    }\n\n    fn operation(&self) -> &Operation {\n        self.pending\n            .checkpoint\n            .operation\n            .as_ref()\n            .expect(\"an operation record always has an operation\")\n    }\n\n    fn operation_mut(&mut self) -> &mut Operation {\n        self.pending\n            .checkpoint\n            .operation\n            .as_mut()\n            .expect(\"an operation record always has an operation\")\n    }\n\n    fn record(&mut self, entry: JournalEntry) -> Result<u32> {\n        let seq = self.operation().journal.len() as u32;\n        self.operation_mut().journal.push(entry);\n        self.write_pending()\n            .map_err(|err| eyre::eyre!(\"could not persist the operation journal: {err:#}\"))?;\n        if self.kind() == OperationKind::Bootstrap\n            && let Some((_, before)) = &self.before\n            && let JournalEntry::PathChanged { path, prior, .. } =","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/scope.rs#L490-L526","documentation":"PendingCheckpoint's operation accessor unwraps checkpoint.operation with expect because an operation record is constructed to always carry an Operation. Panics only if the checkpoint state machine allowed writing/reading a checkpoint without its operation field populated.","triggerScenarios":"Reading a pending checkpoint file (via kind/record/write_outcome paths) whose operation field is missing — e.g. a truncated or hand-edited pending state file, or a code path that serializes a checkpoint before setting operation.","commonSituations":"Corrupted or partially written pending operation state after a crash; manual tampering with mise's history state directory; version skew between writer and reader of the checkpoint format.","solutions":["Delete the corrupt pending checkpoint state so history tracking restarts cleanly","Upgrade/downgrade so the same mise version reads what it wrote","Populate operation before persisting any checkpoint (fix the writer)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// guard before reading pending checkpoints\nif !checkpoint_has_operation(&pending_file) {\n    fs::remove_file(&pending_file).ok(); // discard corrupt state\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid killing mise mid-write to history state files","Don't mix mise versions against one state directory","Validate checkpoint shape at load time and discard invalid files"],"tags":["panic","history","state","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}