jdx/mise · error
failed to uninstall {tv}
Error message
failed to uninstall {tv} What it means
`mise uninstall` wraps any failure from a tool backend's uninstall routine with the context "failed to uninstall {tv}" (the tool@version being removed). The backend error is preserved as the wrapped cause, so this is a contextual wrapper, not a root cause. It is returned (not just warned), so the CLI exits non-zero.
Source
Thrown at src/cli/uninstall.rs:125
};
for (plugin, tv) in to_remove {
let key = format!("{}@{}", tv.ba().short, tv.version);
let tool = progress
.as_ref()
.and_then(|progress| progress.start_tool(&key));
let pr = match &tool {
Some(tool) => tool.reporter(),
None => mpr.add(&tv.style()),
};
let result = plugin
.uninstall_version(&config, &tv, pr.as_ref(), self.is_dry_run())
.await;
if let Some(tool) = &tool {
tool.complete(result.as_ref().err().map(|e| e.to_string()).as_deref());
}
if let Err(err) = result {
error!("{err}");
return Err(eyre!(err).wrap_err(format!("failed to uninstall {tv}")));
}
if self.is_dry_run() {
pr.finish_with_message("uninstalled (dry-run)".into());
} else {
if let Err(err) = crate::tool_purgatory::forget_path(&tv.install_path()) {
warn!("failed to clear tool purgatory entry: {err:#}");
}
if tool.is_none() {
pr.finish_with_message("uninstalled".into());
}
}
}
if let Some(progress) = progress.as_mut() {
progress.finish(vec![]);
}
if self.is_dry_run() {
if self.dry_run_code && has_work {View on GitHub (pinned to afd2eddd3a)
Solutions
- Read the wrapped cause (full `{err:#}` chain via verbose output) to find the backend failure, then fix that specific condition.
- Close processes using the install path (or stop AV scanning) and retry the uninstall.
- If the directory is already gone, remove stale metadata (the version dir under mise's installs path) or reinstall then uninstall.
- Use `mise uninstall --dry-run` first to see what will be removed.
Example fix
// before mise uninstall node@20.0.0 # fails: install dir locked // after pkill -f node; mise uninstall node@20.0.0
Defensive patterns
Strategy: try-catch
Validate before calling
mise ls <tool> # confirm the version exists before uninstalling mise uninstall <tool>@<version> --dry-run
Try / catch
match mise_uninstall(tool, version) {
Err(e) => {
eprintln!("uninstall failed: {e:#}"); // inspect full chain for root cause
// e.g. kill locking processes, then retry once
}
Ok(()) => {}
} Prevention
- Check the tool/version exists before uninstalling.
- Use --dry-run first to preview removals.
- Close running tool processes before removing versions.
- Avoid manually deleting install directories; always go through mise.
When it happens
Trigger: Running `mise uninstall <tool>@<version>` when the backend's uninstall call returns Err — e.g. the install directory is missing but tracked, files are held open / permission-denied on Windows, or the underlying remove fails mid-way. The `tool.complete(...)` hook is invoked with the error string before wrapping.
Common situations: Manually deleted install dirs leaving purgatory/metadata stale; another process (editor, AV, running tool binary) locking files; partial installs; removing a version while a shim or task still uses it.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- relay unavailable
- Plugin {ba} is not installed
- {name} does not support declarative package removal
- package plugin '{}' does not support uninstall; add hooks/pa
- multiple tools specified, use --all to uninstall all version
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/a9d32d0dc8cf8223.
Report an issue: GitHub.