jdx/mise · error

multiple tools specified, use --all to uninstall all version

Error message

multiple tools specified, use --all to uninstall all versions

What it means

`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.

Source

Thrown at src/cli/uninstall.rs:72

impl Uninstall {
    pub(super) fn is_dry_run(&self) -> bool {
        self.dry_run || self.dry_run_code
    }

    pub(crate) async fn run(self) -> Result<()> {
        let config = Config::get().await?;
        let tool_versions = if self.installed_tool.is_empty() && self.all {
            self.get_all_tool_versions(&config).await?
        } else {
            self.get_requested_tool_versions(&config).await?
        };
        let tool_versions = tool_versions
            .into_iter()
            .unique_by(|(_, tv)| (tv.request.ba().short.clone(), tv.version.clone()))
            .collect::<Vec<_>>();
        if !self.all && tool_versions.len() > self.installed_tool.len() {
            bail!("multiple tools specified, use --all to uninstall all versions");
        }
        let removed_install_paths = tool_versions
            .iter()
            .map(|(_, tv)| tv.install_path())
            .collect::<Vec<_>>();

        let mpr = MultiProgressReport::get();
        let mut to_remove = Vec::with_capacity(tool_versions.len());
        for (plugin, tv) in tool_versions {
            // `is_version_installed` resolves the install path, so it says no for a link whose
            // target is gone -- and that entry is precisely what someone running `uninstall` is
            // trying to get rid of. Refusing it left the name occupied with no command able to
            // free it. It is still not *installed*: this only decides whether there is something
            // here to remove.
            if !plugin.is_version_installed(&config, &tv, true)
                && !file::entry_exists(tv.install_path())
            {
                warn!("{} is not installed", tv.style());

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Pass `--all` to uninstall all installed versions: `mise uninstall node --all`.
  2. Specify the exact version: `mise uninstall node@20.1.0`.
  3. List installed versions with `mise ls node` to decide which to remove.

Example fix

// before
mise uninstall node
// after
mise uninstall node --all
# or
mise uninstall node@20.1.0
Defensive patterns

Strategy: validation

Validate before calling

[ "$(mise ls node --json | jq 'length')" -gt 1 ] && mise uninstall node --all || mise uninstall node

Prevention

When it happens

Trigger: Running `mise uninstall <tool>` (no version suffix) when more than one version of the tool is installed, without `--all`, in run().

Common situations: 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.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/f4b4d1b09b7b4c06. Report an issue: GitHub.