jdx/mise · error
package plugin '{}' does not support uninstall; add hooks/pa
Error message
package plugin '{}' does not support uninstall; add hooks/package_uninstall.lua What it means
A package plugin can only uninstall packages if it provides a hooks/package_uninstall.lua hook. During apply_prune_plan, after computing packages that should be removed, mise refuses to proceed when the plugin lacks uninstall support rather than silently leaving installed packages behind.
Source
Thrown at src/system/packages/plugin.rs:444
let before = self.installed(&requests).await?;
let present = before
.iter()
.filter_map(|status| {
Self::status_version(status).map(|version| PackageRequest {
name: status.request.name.clone(),
version: Some(version),
tap_url: None,
desired: crate::system::packages::PackageDesiredState::Present,
})
})
.collect::<Vec<_>>();
Self::reconcile_missing_ownership(&mut state, &before);
self.save_state(&state)?;
if present.is_empty() {
return Ok(0);
}
if !self.supports_uninstall() {
bail!(
"package plugin '{}' does not support uninstall; add hooks/package_uninstall.lua",
self.name
);
}
let action_result = self.uninstall_action(&present).await;
let after = self.installed(&present).await;
let after = match after {
Ok(after) => after,
Err(status_err) => {
if let Err(action_err) = action_result {
warn!(
"{}: failed to verify uninstall after error: {status_err:#}",
self.name
);
return Err(action_err);
}
return Err(status_err);View on GitHub (pinned to afd2eddd3a)
Solutions
- Add a hooks/package_uninstall.lua to the plugin implementing package removal
- Uninstall the package manually with the underlying manager and clear ownership state, then prune once uninstall support exists
- Keep the package installed (don't remove it from config) if the plugin cannot uninstall
- Update the plugin to a version that ships package_uninstall.lua
Example fix
// before: plugin dir lacks the hook mise plugins packages prune myplugin // error: package plugin 'myplugin' does not support uninstall // after: add hooks/package_uninstall.lua -- function mise_package_uninstall(ctx) ... end mise plugins packages prune myplugin
Defensive patterns
Strategy: validation
Validate before calling
let hook = plugin.dir().join("hooks/package_uninstall.lua");
if !hook.exists() { /* skip prune or uninstall manually */ } Type guard
fn supports_uninstall(dir: &Path) -> bool { dir.join("hooks/package_uninstall.lua").is_file() } Try / catch
match plugin.prune().await {
Err(e) if e.to_string().contains("does not support uninstall") => {
warn("plugin cannot uninstall; removing packages manually"); manual_uninstall_tracked()
}
other => other,
} Prevention
- Check the plugin ships hooks/package_uninstall.lua before enabling prune workflows
- Only remove packages from config for plugins with uninstall support
- Keep plugins updated to versions with full install/check/uninstall hook coverage
When it happens
Trigger: A prune/uninstall operation (apply_prune_plan) targets packages that must be removed, but the plugin directory has no hooks/package_uninstall.lua so supports_uninstall() returns false.
Common situations: Using a plugin written only for installation (install/check hooks) and later trying `mise packages prune` or removing the package from config; older plugin versions predating the uninstall hook convention.
Related errors
- package plugin '{plugin_name}' is not a tool backend
- {name} does not support declarative package removal
- package plugin '{}' does not support uninstall; add hooks/pa
- pre_use hook is not implemented
- {tool}'s bin/install exited successfully but installed nothi
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/e487fba224a57868.
Report an issue: GitHub.