{"record":{"id":"5b04db12cb259e4f","repo":"rtk-ai/rtk","slug":"failed-to-uninstall-rtk-from-one-or-more-droid-hook-files","errorCode":null,"errorMessage":"Failed to uninstall RTK from one or more Droid hook files:\n  - {}","messagePattern":"Failed to uninstall RTK from one or more Droid hook files:\n  - (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/hooks/init.rs","lineNumber":3745,"sourceCode":"    }\n    Ok(())\n}\n\nfn uninstall_droid_at(droid_dir: &Path, ctx: InitContext) -> Result<Vec<String>> {\n    let mut removed = Vec::new();\n    let mut errors = Vec::new();\n    for candidate in droid_hook_file_candidates(droid_dir) {\n        match remove_droid_hook_from_file(&candidate, ctx) {\n            Ok(true) => {\n                removed.push(format!(\"Droid hook file: {}\", candidate.path.display()));\n            }\n            Ok(false) => {}\n            Err(error) => errors.push(format!(\"{}: {error:#}\", candidate.path.display())),\n        }\n    }\n\n    if !errors.is_empty() {\n        return Err(anyhow::anyhow!(\n            \"Failed to uninstall RTK from one or more Droid hook files:\\n  - {}\",\n            errors.join(\"\\n  - \")\n        ));\n    }\n\n    Ok(removed)\n}\n\n/// Strip the RTK entry from one Droid hook file. Returns true if the file\n/// held an RTK entry (and was rewritten, unless dry-run).\nfn remove_droid_hook_from_file(file: &DroidHookFile, ctx: InitContext) -> Result<bool> {\n    let InitContext {\n        verbose, dry_run, ..\n    } = ctx;\n    let path = &file.path;\n\n    let mut root = match read_json_file(path)? {\n        Some(v) => v,","sourceCodeStart":3727,"sourceCodeEnd":3763,"githubUrl":"https://github.com/rtk-ai/rtk/blob/0924356b4caba4989607227b7c8824d3d8098719/src/hooks/init.rs#L3727-L3763","documentation":"During `rtk init` uninstall, RTK tries to remove its hooks from every known Droid hook file. If removal from any candidate file fails, all per-file errors are collected and returned together as this aggregated anyhow error.","triggerScenarios":"Running the Droid uninstall path when one or more hook files cannot be processed: unreadable file, permission denied on write, malformed JSON that prevents hook removal, or the file path being a directory/symlink target that is missing.","commonSituations":"Hook files owned by another user or made read-only; partial/corrupt Droid config after a failed upgrade; files manually edited so the RTK hook JSON no longer matches what uninstall expects.","solutions":["Read the per-file messages after the header to see which files failed and why.","Fix permissions on the listed files (chown/chmod) and re-run the uninstall.","Manually remove the RTK hook entries from the failing JSON hook files if automated removal keeps failing.","Restore the hook files to a valid state (reinstall/reconfigure Droid) and retry."],"exampleFix":"// before\n$ rtk init --uninstall  # fails: permission denied\n// after\nchmod u+w ~/.droid/hooks.json && rtk init --uninstall","handlingStrategy":"try-catch","validationCode":"import json, os\nfor p in ['~/.droid/hooks.json']:\n    path = os.path.expanduser(p)\n    if not os.access(path, os.W_OK):\n        raise PermissionError(f'{path} is not writable')\n    json.load(open(path))  # must be valid JSON for hook removal","typeGuard":null,"tryCatchPattern":"match rtk_uninstall_droid() {\n    Err(e) if e.to_string().starts_with(\"Failed to uninstall RTK from one or more Droid hook files\") => {\n        // parse per-file errors, fix permissions/JSON, retry\n    }\n    other => other,\n}","preventionTips":["Keep Droid hook files writable by your user and valid JSON","Do not hand-edit hook files while rtk owns entries","Back up hook files before running uninstall"],"tags":["uninstall","hooks","file-io"],"backgroundTag":"file-write-failed","analyzedSha":"0924356b4caba4989607227b7c8824d3d8098719","analyzedAt":"2026-09-19T19:25:29.612Z","contentChangedAt":"2026-09-19T19:25:29.612Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}