{"record":{"id":"e487fba224a57868","repo":"jdx/mise","slug":"package-plugin-does-not-support-uninstall-ad-e487fb","errorCode":null,"errorMessage":"package plugin '{}' does not support uninstall; add hooks/package_uninstall.lua","messagePattern":"package plugin '(.+?)' does not support uninstall; add hooks/package_uninstall\\.lua","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/plugin.rs","lineNumber":444,"sourceCode":"        let before = self.installed(&requests).await?;\n        let present = before\n            .iter()\n            .filter_map(|status| {\n                Self::status_version(status).map(|version| PackageRequest {\n                    name: status.request.name.clone(),\n                    version: Some(version),\n                    tap_url: None,\n                    desired: crate::system::packages::PackageDesiredState::Present,\n                })\n            })\n            .collect::<Vec<_>>();\n        Self::reconcile_missing_ownership(&mut state, &before);\n        self.save_state(&state)?;\n        if present.is_empty() {\n            return Ok(0);\n        }\n        if !self.supports_uninstall() {\n            bail!(\n                \"package plugin '{}' does not support uninstall; add hooks/package_uninstall.lua\",\n                self.name\n            );\n        }\n\n        let action_result = self.uninstall_action(&present).await;\n        let after = self.installed(&present).await;\n        let after = match after {\n            Ok(after) => after,\n            Err(status_err) => {\n                if let Err(action_err) = action_result {\n                    warn!(\n                        \"{}: failed to verify uninstall after error: {status_err:#}\",\n                        self.name\n                    );\n                    return Err(action_err);\n                }\n                return Err(status_err);","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/plugin.rs#L426-L462","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: plugin dir lacks the hook\nmise plugins packages prune myplugin\n// error: package plugin 'myplugin' does not support uninstall\n// after: add hooks/package_uninstall.lua\n-- function mise_package_uninstall(ctx) ... end\nmise plugins packages prune myplugin","handlingStrategy":"validation","validationCode":"let hook = plugin.dir().join(\"hooks/package_uninstall.lua\");\nif !hook.exists() { /* skip prune or uninstall manually */ }","typeGuard":"fn supports_uninstall(dir: &Path) -> bool { dir.join(\"hooks/package_uninstall.lua\").is_file() }","tryCatchPattern":"match plugin.prune().await {\n    Err(e) if e.to_string().contains(\"does not support uninstall\") => {\n        warn(\"plugin cannot uninstall; removing packages manually\"); manual_uninstall_tracked()\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["plugin","uninstall","missing-hook","unsupported-operation"],"backgroundTag":"operation-not-supported","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"}