{"record":{"id":"4465ac309668c1bd","repo":"larksuite/cli","slug":"separate-skills-sync-failed-s","errorCode":null,"errorMessage":"separate skills sync failed: %s","messagePattern":"separate skills sync failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skillscheck/sync.go","lineNumber":465,"sourceCode":"\t\t\tStateReadable:  true,\n\t\t\tForce:          opts.Force,\n\t\t})\n\t\tplan = &fallback\n\t}\n\n\tvar installResult *selfupdate.NpmResult\n\tofficialUnknown := plan == nil\n\tif plan == nil {\n\t\tinstallResult = opts.Runner.InstallAllSkills(githubSkillsSource)\n\t} else if len(plan.ToUpdate) > 0 {\n\t\tinstallResult = opts.Runner.InstallSkills(githubSkillsSource, plan.ToUpdate)\n\t}\n\tif installResult != nil && installResult.Err != nil {\n\t\treasons = append(reasons, githubSkillsSource+\": \"+resultDetail(installResult))\n\t\treturn &SyncResult{\n\t\t\tAction: \"failed\",\n\t\t\tLayout: LayoutSeparate,\n\t\t\tErr:    fmt.Errorf(\"separate skills sync failed: %s\", strings.Join(reasons, \"; \")),\n\t\t\tDetail: strings.Join(reasons, \"\\n\"),\n\t\t\tForce:  opts.Force,\n\t\t}\n\t}\n\tif hasInstalledSkill(installed, \"lark-suite\") {\n\t\tif result := opts.Runner.RemoveGlobalSkills([]string{\"lark-suite\"}); result == nil || result.Err != nil {\n\t\t\treturn &SyncResult{Action: \"failed\", Layout: LayoutSeparate, Err: fmt.Errorf(\"remove lark-suite failed: %s\", resultDetail(result)), Force: opts.Force}\n\t\t}\n\t}\n\tif plan == nil {\n\t\tempty := SyncPlan{Version: opts.Version}\n\t\tplan = &empty\n\t}\n\twarning := \"\"\n\tif installResult != nil {\n\t\twarning = \"used the GitHub legacy fallback; installed Skill content may be incomplete because the legacy protocol can ignore individual file download failures\"\n\t}\n\treturn finishSync(opts, LayoutSeparate, *plan, \"fallback_synced\", warning, officialUnknown)","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/skillscheck/sync.go#L447-L483","documentation":"fallbackSeparate runs when the primary sync (suite/v0.2 index) fails and falls back to the legacy GitHub-based separate-skills installation. It installs all planned skills from the GitHub source via InstallAllSkills/InstallSkills; if that install result carries an error (or the source request failed, recorded in `reasons`), it returns a failed SyncResult wrapping all accumulated failure reasons in the message 'separate skills sync failed'.","triggerScenarios":"Calling SyncSkills when the primary source fetch failed (reasons already populated) and the GitHub legacy fallback install also fails — runner.InstallAllSkills(githubSkillsSource) or runner.InstallSkills(githubSkillsSource, plan.ToUpdate) returns a non-nil Err. The message joins all reasons with '; ', so both the primary failure and the GitHub install failure appear.","commonSituations":"Both the primary skills source and raw GitHub access are unreachable (offline, proxy/firewall blocking github.com or raw.githubusercontent.com); the GitHub repo or branch moved so the legacy source 404s; rate-limiting of unauthenticated GitHub requests; npm install failing on the fetched archive.","solutions":["Read the joined reasons in Detail/message to see the primary and GitHub failure causes and fix the underlying network/auth issue first.","Restore connectivity to github.com and the npm registry (check proxy/VPN/firewall settings) and retry the sync.","Verify the GitHub skills source repository/branch still exists and the pinned source URL matches the CLI version; upgrade the CLI if the source moved.","Check GitHub API rate limits (unauthenticated requests are limited) and retry later or provide credentials.","If the suite source is healthy, fix the original primary-source failure so the GitHub fallback is not needed."],"exampleFix":"// before: primary index fetch fails, then GitHub fallback also fails\n//   Err: \"separate skills sync failed: <primary>: index request failed: timeout; github: ... 404\"\n// after: validate source reachability before choosing the fallback\nif !reachable(githubSkillsSource) {\n    return &SyncResult{Action: \"failed\", Err: fmt.Errorf(\"no reachable skills source (primary: %v; github unreachable)\", reasons), Force: opts.Force}\n}\ninstallResult = opts.Runner.InstallAllSkills(githubSkillsSource)","handlingStrategy":"fallback","validationCode":"// verify sources before attempting the legacy fallback\nfor _, src := range []string{primarySource, githubSkillsSource} {\n    resp, err := http.Head(src)\n    if err != nil || resp.StatusCode >= 400 {\n        return fmt.Errorf(\"skills source unreachable: %s\", src)\n    }\n}\n// unauthenticated GitHub requests are rate limited; provide credentials in CI","typeGuard":"func fallbackInstallOK(r *selfupdate.NpmResult) bool { return r != nil && r.Err == nil }","tryCatchPattern":"res := SyncSkills(opts)\nif res != nil && res.Err != nil && strings.HasPrefix(res.Err.Error(), \"separate skills sync failed\") {\n    for _, reason := range strings.Split(res.Detail, \"\\n\") {\n        log.Printf(\"sync failure reason: %s\", reason) // fix each underlying cause\n    }\n    // retry after restoring network/auth to the sources\n}","preventionTips":["Ensure outbound access to both the primary source and github.com/raw.githubusercontent.com.","Provide GitHub credentials in CI to avoid unauthenticated rate limits.","Keep the CLI updated so pinned GitHub source URLs stay valid.","Treat the fallback warning (legacy protocol can ignore file download failures) as a cue to verify installed skill content after a fallback sync."],"tags":["skills-sync","github","network","fallback","npm"],"backgroundTag":"skills-sync-fallback-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"}