{"record":{"id":"3c911987393c499a","repo":"jdx/mise","slug":"choose-explicit-paths-or-all-not-both","errorCode":null,"errorMessage":"choose explicit paths or `--all`, not both","messagePattern":"choose explicit paths or `--all`, not both","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/replay.rs","lineNumber":112,"sourceCode":"    from: String,\n    to: String,\n    /// The permission bits the checkpoint recorded for the file (only\n    /// modes git cannot express, `0600` say), and for the directories\n    /// above it.\n    bits: Option<u32>,\n    dir_bits: Vec<(PathBuf, u32)>,\n}\n\n/// One checkpoint and the paths to take from it.\nstruct Target {\n    entry: Entry,\n    paths: Vec<PathBuf>,\n}\n\npub(crate) async fn rollback(req: RollbackRequest) -> Result<()> {\n    ensure_enabled()?;\n    if req.all && !req.paths.is_empty() {\n        bail!(\"choose explicit paths or `--all`, not both\");\n    }\n    if req.paths.is_empty() && !(req.to.is_some() && req.all) {\n        bail!(\n            \"name the paths to roll back, or `--to <ref> --all` for everything the checkpoint covers\"\n        );\n    }\n    if req.to.is_none() && req.all {\n        bail!(\"`--all` needs `--to <ref>`\");\n    }\n    let (store, tracked, entries) = crate::cli::dotfiles::history::open().await?;\n    let repo = store\n        .repo()\n        .ok_or_else(|| eyre::eyre!(\"rolling back requires git\"))?;\n    let live = live_tree(repo, &tracked)?;\n    let paths: Vec<PathBuf> = req\n        .paths\n        .iter()\n        .map(|path| normalize_target(path))","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/replay.rs#L94-L130","documentation":"mise's dotfiles history rollback validates that the RollbackRequest is unambiguous before doing any git work. If the caller passes both explicit paths and the --all flag, mise cannot tell whether the user wants to restore just those paths or everything the checkpoint covers, so it refuses immediately with this bail!. This is a pure argument-validation guard at the top of rollback in src/system/history/replay.rs.","triggerScenarios":"Calling rollback (e.g. `mise bootstrap dotfiles rollback <paths> --all` or constructing RollbackRequest with all=true and a non-empty paths vec). Any request where req.all && !req.paths.is_empty().","commonSituations":"Users scripting a rollback append --all to an already-specified path list; shell aliases that always add --all; users confusing --all with \"include all named paths\".","solutions":["Pass either explicit paths OR --all, never both","Use explicit paths to restore specific files","Use `--to <ref> --all` to restore everything the checkpoint covers"],"exampleFix":"// before\nmise bootstrap dotfiles rollback ~/.zshrc --all\n// after\nmise bootstrap dotfiles rollback ~/.zshrc\n// or\nmise bootstrap dotfiles rollback --to <ref> --all","handlingStrategy":"validation","validationCode":"if (args.all && args.paths.length > 0) {\n  throw new Error(\"choose explicit paths or --all, not both\");\n}","typeGuard":"const isExclusive = (req: { all: boolean; paths: string[] }) =>\n  !(req.all && req.paths.length > 0);","tryCatchPattern":"try {\n  await rollback(req);\n} catch (e) {\n  if (String(e).includes(\"not both\")) {\n    req.paths = [];\n    await rollback(req);\n  } else throw e;\n}","preventionTips":["Build CLI parsing so --all clears/forbids positional paths","Add a unit test asserting the two options are mutually exclusive","Show --all and <paths> as separate usage lines in help text"],"tags":["cli","argument-validation","mutually-exclusive"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}