{"record":{"id":"7ae4b107d4f8a8f1","repo":"larksuite/cli","slug":"remove-lark-suite-failed-s","errorCode":null,"errorMessage":"remove lark-suite failed: %s","messagePattern":"remove lark-suite failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skillscheck/sync.go","lineNumber":434,"sourceCode":"\t\t}\n\t}\n\tsort.Strings(names)\n\treturn names, nil\n}\n\nfunc syncLayout(runner SkillsRunner, source string, layout Layout, plan SyncPlan, installed []installedSkill) error {\n\tif layout == LayoutSuite {\n\t\treturn syncSuite(runner, source, plan, installed)\n\t}\n\tif len(plan.ToUpdate) > 0 {\n\t\tresult := runner.InstallSkills(source, plan.ToUpdate)\n\t\tif result == nil || result.Err != nil {\n\t\t\treturn fmt.Errorf(\"archive install failed: %s\", resultDetail(result))\n\t\t}\n\t}\n\tif hasInstalledSkill(installed, \"lark-suite\") {\n\t\tif result := runner.RemoveGlobalSkills([]string{\"lark-suite\"}); result == nil || result.Err != nil {\n\t\t\treturn fmt.Errorf(\"remove lark-suite failed: %s\", resultDetail(result))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fallbackSeparate(opts SyncOptions, previous *SkillsState, readable bool, local []string, installed []installedSkill, plan *SyncPlan, reasons []string) *SyncResult {\n\tif plan == nil && readable && previous != nil && len(previous.OfficialSkills) > 0 {\n\t\tfallback := PlanSync(SyncInput{\n\t\t\tVersion:        opts.Version,\n\t\t\tOfficialSkills: previous.OfficialSkills,\n\t\t\tLocalSkills:    local,\n\t\t\tPreviousState:  previous,\n\t\t\tStateReadable:  true,\n\t\t\tForce:          opts.Force,\n\t\t})\n\t\tplan = &fallback\n\t}\n","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/skillscheck/sync.go#L416-L452","documentation":"syncLayout's archive path, after installing individual skills, removes the legacy 'lark-suite' wrapper skill when it is still installed (migrating from suite to separate layout). This error is returned when runner.RemoveGlobalSkills([\"lark-suite\"]) returns nil or a result with Err set — i.e. the npm global uninstall of the suite package failed.","triggerScenarios":"Calling SyncSkills with archive layout when hasInstalledSkill(installed, \"lark-suite\") is true and runner.RemoveGlobalSkills fails — e.g. the npm uninstall exits non-zero due to permissions, the package was modified externally, or npm is not on PATH.","commonSituations":"Global prefix owned by root or another user (EACCES); nvm prefix switched between install and removal so the package is 'missing' to npm; the package directory was manually deleted leaving npm metadata inconsistent; concurrent package managers (pnpm/yarn global) claiming the package.","solutions":["Inspect the %s detail in the message for the exact npm uninstall error, then fix it (usually permissions or a changed global prefix).","Run the removal manually (`npm uninstall -g <suite-package>`) with the same npm/prefix the CLI uses, then re-run sync.","Fix global-prefix permissions (chown the prefix or use a user-owned nvm prefix) before retrying.","If the suite directory was manually removed, reinstall it once so npm can cleanly uninstall it."],"exampleFix":"// before: npm uninstall fails with EACCES\nif result := runner.RemoveGlobalSkills([]string{\"lark-suite\"}); result == nil || result.Err != nil {\n    return fmt.Errorf(\"remove lark-suite failed: %s\", resultDetail(result))\n}\n// after: ensure a writable, consistent global prefix first\n//   npm config set prefix ~/.npm-global  (and add to PATH)\n// then retry the sync so RemoveGlobalSkills succeeds","handlingStrategy":"validation","validationCode":"// before removal: confirm npm can see and remove the package\nsuite, _ := findSkill(installed, \"lark-suite\")\nif suite.Path != \"\" {\n    if _, err := os.Stat(suite.Path); err != nil {\n        // package dir missing -> npm uninstall will fail; repair first\n    }\n}\n// also confirm the npm global prefix is writable before attempting removal","typeGuard":"func removalOK(r *selfupdate.NpmResult) bool { return r != nil && r.Err == nil }","tryCatchPattern":"if result := runner.RemoveGlobalSkills([]string{\"lark-suite\"}); result == nil || result.Err != nil {\n    // retry once after repairing npm state, e.g. `npm uninstall -g <suite>` manually\n    if retry := runner.RemoveGlobalSkills([]string{\"lark-suite\"}); retry != nil && retry.Err == nil {\n        return nil\n    }\n    return fmt.Errorf(\"remove lark-suite failed: %s\", resultDetail(result))\n}","preventionTips":["Use a user-owned npm global prefix (nvm) to avoid EACCES on uninstall.","Do not manually delete global package directories; use npm uninstall.","Keep the same npm/prefix for install, listing, and removal within one sync run.","Inspect the npm error detail before retrying to address the root cause (permissions vs missing package)."],"tags":["npm","uninstall-failed","skills-sync","permissions"],"backgroundTag":"npm-uninstall-failed","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}