{"record":{"id":"02695642ea39c891","repo":"pbakaus/impeccable","slug":"update-failed-e","errorCode":null,"errorMessage":"Update failed: {e}","messagePattern":"Update failed: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/skills/src/commands.rs","lineNumber":842,"sourceCode":"                copy_provider_hooks(&sys, &tmp_dir, &root, &copy_providers, force, None).map_err(Flow::Throw)?\n            } else {\n                Vec::new()\n            };\n            Ok(hook_targets)\n        })();\n        util::rm_rf(&tmp_dir);\n        return match outcome {\n            Ok(hook_targets) => {\n                let v = sys.get_skills_version(&root, scope);\n                out(io, &format!(\"Skills are up to date{}.\", version_suffix(&v)));\n                if !hook_targets.is_empty() {\n                    out(io, &format!(\"Installed hooks into: {}\", hook_targets.join(\", \")));\n                }\n                out(io, \"Nothing else to do.\");\n                Err(Flow::Exit(0))\n            }\n            Err(Flow::Throw(e)) => {\n                err(io, &format!(\"Update failed: {e}\"));\n                Err(Flow::Exit(1))\n            }\n            // JS: the try/catch around decideHookInstall swallows the prompt\n            // abort too, printing its message.\n            Err(Flow::Abort) => {\n                err(io, \"Update failed: Aborted.\");\n                Err(Flow::Exit(1))\n            }\n            Err(other) => Err(other),\n        };\n    }\n\n    out(io, &format!(\"Found skills in: {}\", copy_providers.join(\", \")));\n\n    if !yes {\n        let ans = prompt.ask(io, &format!(\"Update skills in {} provider folder(s)? (Y/n) \", copy_providers.len()))?;\n        if ans == \"n\" || ans == \"no\" {\n            util::rm_rf(&tmp_dir);","sourceCodeStart":824,"sourceCodeEnd":860,"githubUrl":"https://github.com/pbakaus/impeccable/blob/2bc2879276c1f321a53c4ca99d3371e411329b52/crates/skills/src/commands.rs#L824-L860","documentation":"Inside the post-download update flow, errors from the update steps (e.g. comparing versions, copying skills, deciding hook installation) arrive as Flow::Throw(e) and are printed as 'Update failed: {e}' with exit 1. This is the generic error arm of the update result match.","triggerScenarios":"`update` when any inner step returns Flow::Throw: file copy failures while updating skills, version-check IO errors, or errors from hook installation logic.","commonSituations":"Read-only or partially locked harness folders during overwrite; filesystem errors mid-update; corrupted existing installation state that cannot be reconciled.","solutions":["Inspect the inner `{e}` message for the root cause (permissions, missing files).","Ensure target harness folders are writable before running update.","Run with --no-hooks to isolate hook-install failures.","As a last resort, delete the skills folder and run `impeccable install` fresh."],"exampleFix":"// before\nimpeccable update  # Update failed: Permission denied writing .cursor/skills\n// after\nchmod -R u+w .cursor && impeccable update --providers=.cursor","handlingStrategy":"try-catch","validationCode":"for d in .claude .cursor; do [ -w \"$d\" ] || echo \"$d not writable\"; done","typeGuard":null,"tryCatchPattern":"if ! impeccable update --providers=.claude; then\n  echo \"update failed ($?) — falling back to fresh install\"\n  impeccable install --providers=.claude --force\nfi","preventionTips":["Keep harness folders writable by the running user.","Run update with --no-hooks to narrow the failure surface in CI.","Fix the root cause printed in {e} before retrying, don't loop blindly."],"tags":["update","filesystem","cli"],"backgroundTag":"file-write-failed","analyzedSha":"2bc2879276c1f321a53c4ca99d3371e411329b52","analyzedAt":"2026-09-08T04:51:14.109Z","contentChangedAt":"2026-09-08T04:51:14.109Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}