{"record":{"id":"499f043a6e3a7c1a","repo":"jdx/mise","slug":"checked-by-the-caller","errorCode":null,"errorMessage":"checked by the caller","messagePattern":"checked by the caller","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/replay.rs","lineNumber":398,"sourceCode":"\nfn sources_of(targets: &[Target]) -> Vec<OperationSource> {\n    targets\n        .iter()\n        .map(|target| OperationSource {\n            checkpoint: target.entry.checkpoint.uuid.clone(),\n            paths: target.paths.iter().map(display_path).collect(),\n        })\n        .collect()\n}\n\nasync fn execute(\n    exec: Execution,\n    store: &Store,\n    tracked: &TrackedSet,\n    entries: &[Entry],\n    live: String,\n) -> Result<()> {\n    let repo = store.repo().expect(\"checked by the caller\");\n    let mut steps = plan(repo, &exec, &live)?;\n    print_plan(&steps, &exec, tracked)?;\n    if exec.dry_run {\n        return Ok(());\n    }\n    let conflicts: Vec<&Step> = steps\n        .iter()\n        .filter(|step| matches!(step.action, Action::Conflict(_)))\n        .collect();\n    if !conflicts.is_empty() {\n        // `--force` answers a type change only (and undo already forces);\n        // an occupant history never captured stays a conflict whatever is\n        // passed, so it is not offered where it would not help\n        let type_changes = conflicts.iter().any(\n            |step| matches!(&step.action, Action::Conflict(reason) if reason.contains(\" became \")),\n        );\n        let hint = if !exec.force && type_changes {\n            \"; pass --force to replace a path whose type changed\"","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/replay.rs#L380-L416","documentation":"execute unwraps store.repo() with expect(\"checked by the caller\"), asserting that callers (rollback, undo) have already verified the history Store has a git repository. If the repo is absent, this invariant was violated upstream and the code panics instead of returning a graceful error.","triggerScenarios":"Calling rollback or undo without a prior existence check on the history store's repository — e.g. running undo when the history directory has no git repo initialized (history disabled, fresh install, or .git removed).","commonSituations":"Running `mise undo` after the history store directory was deleted or corrupted; environments where history tracking was never initialized; tampered history storage.","solutions":["Ensure the history store repo exists before invoking rollback/undo (check and initialize it in the caller)","Reinitialize the history store so its git repository is created","Report the missing-repo condition as a normal error in execute instead of expect"],"exampleFix":"// before\nlet repo = store.repo().expect(\"checked by the caller\");\n// after\nlet Some(repo) = store.repo() else {\n    return Err(anyhow!(\"history store repository not initialized; run the command that first records history\"));\n};","handlingStrategy":"validation","validationCode":"// caller-side guard before undo/rollback\nif !history_store_initialized() {\n    eprintln!(\"history store not initialized; nothing to undo\");\n    return;\n}","typeGuard":"fn has_repo(store: &Store) -> bool {\n    store.repo().is_some()\n}","tryCatchPattern":"match store.repo() {\n    Some(repo) => execute_with(repo, ...),\n    None => bail!(\"history repository missing; reinitialize history store\"),\n}","preventionTips":["Do not delete mise's history state directory manually","Initialize history tracking before relying on undo/rollback","Convert expects at public entry points into typed errors"],"tags":["panic","git","history","invariant","undo"],"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"}