{"record":{"id":"f4b4d1b09b7b4c06","repo":"jdx/mise","slug":"multiple-tools-specified-use-all-to-uninstall-a","errorCode":null,"errorMessage":"multiple tools specified, use --all to uninstall all versions","messagePattern":"multiple tools specified, use --all to uninstall all versions","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/uninstall.rs","lineNumber":72,"sourceCode":"\nimpl Uninstall {\n    pub(super) fn is_dry_run(&self) -> bool {\n        self.dry_run || self.dry_run_code\n    }\n\n    pub(crate) async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let tool_versions = if self.installed_tool.is_empty() && self.all {\n            self.get_all_tool_versions(&config).await?\n        } else {\n            self.get_requested_tool_versions(&config).await?\n        };\n        let tool_versions = tool_versions\n            .into_iter()\n            .unique_by(|(_, tv)| (tv.request.ba().short.clone(), tv.version.clone()))\n            .collect::<Vec<_>>();\n        if !self.all && tool_versions.len() > self.installed_tool.len() {\n            bail!(\"multiple tools specified, use --all to uninstall all versions\");\n        }\n        let removed_install_paths = tool_versions\n            .iter()\n            .map(|(_, tv)| tv.install_path())\n            .collect::<Vec<_>>();\n\n        let mpr = MultiProgressReport::get();\n        let mut to_remove = Vec::with_capacity(tool_versions.len());\n        for (plugin, tv) in tool_versions {\n            // `is_version_installed` resolves the install path, so it says no for a link whose\n            // target is gone -- and that entry is precisely what someone running `uninstall` is\n            // trying to get rid of. Refusing it left the name occupied with no command able to\n            // free it. It is still not *installed*: this only decides whether there is something\n            // here to remove.\n            if !plugin.is_version_installed(&config, &tv, true)\n                && !file::entry_exists(tv.install_path())\n            {\n                warn!(\"{} is not installed\", tv.style());","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/cli/uninstall.rs#L54-L90","documentation":"`mise uninstall` matched multiple versions (of one or more tools) but `--all` was not passed, so mise refuses to guess which versions to remove. The guard fires when the deduplicated tool/version set is larger than the number of explicitly named tools.","triggerScenarios":"Running `mise uninstall <tool>` (no version suffix) when more than one version of the tool is installed, without `--all`, in run().","commonSituations":"A tool has accumulated several installed versions; user runs `mise uninstall node` expecting removal of the active one only or all — mise demands explicitness via --all or an explicit version.","solutions":["Pass `--all` to uninstall all installed versions: `mise uninstall node --all`.","Specify the exact version: `mise uninstall node@20.1.0`.","List installed versions with `mise ls node` to decide which to remove."],"exampleFix":"// before\nmise uninstall node\n// after\nmise uninstall node --all\n# or\nmise uninstall node@20.1.0","handlingStrategy":"validation","validationCode":"[ \"$(mise ls node --json | jq 'length')\" -gt 1 ] && mise uninstall node --all || mise uninstall node","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check `mise ls <tool>` for multiple versions before uninstalling.","Always pass an explicit version or --all in scripts.","Avoid bare `mise uninstall <tool>` in automation."],"tags":["cli","uninstall","ambiguous-argument"],"backgroundTag":"missing-required-flag","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}