larksuite/cli · error
separate skills sync failed: %s
Error message
separate skills sync failed: %s
What it means
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'.
Source
Thrown at internal/skillscheck/sync.go:465
StateReadable: true,
Force: opts.Force,
})
plan = &fallback
}
var installResult *selfupdate.NpmResult
officialUnknown := plan == nil
if plan == nil {
installResult = opts.Runner.InstallAllSkills(githubSkillsSource)
} else if len(plan.ToUpdate) > 0 {
installResult = opts.Runner.InstallSkills(githubSkillsSource, plan.ToUpdate)
}
if installResult != nil && installResult.Err != nil {
reasons = append(reasons, githubSkillsSource+": "+resultDetail(installResult))
return &SyncResult{
Action: "failed",
Layout: LayoutSeparate,
Err: fmt.Errorf("separate skills sync failed: %s", strings.Join(reasons, "; ")),
Detail: strings.Join(reasons, "\n"),
Force: opts.Force,
}
}
if hasInstalledSkill(installed, "lark-suite") {
if result := opts.Runner.RemoveGlobalSkills([]string{"lark-suite"}); result == nil || result.Err != nil {
return &SyncResult{Action: "failed", Layout: LayoutSeparate, Err: fmt.Errorf("remove lark-suite failed: %s", resultDetail(result)), Force: opts.Force}
}
}
if plan == nil {
empty := SyncPlan{Version: opts.Version}
plan = &empty
}
warning := ""
if installResult != nil {
warning = "used the GitHub legacy fallback; installed Skill content may be incomplete because the legacy protocol can ignore individual file download failures"
}
return finishSync(opts, LayoutSeparate, *plan, "fallback_synced", warning, officialUnknown)View on GitHub (pinned to 7fd6ef3c07)
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.
Example fix
// before: primary index fetch fails, then GitHub fallback also fails
// Err: "separate skills sync failed: <primary>: index request failed: timeout; github: ... 404"
// after: validate source reachability before choosing the fallback
if !reachable(githubSkillsSource) {
return &SyncResult{Action: "failed", Err: fmt.Errorf("no reachable skills source (primary: %v; github unreachable)", reasons), Force: opts.Force}
}
installResult = opts.Runner.InstallAllSkills(githubSkillsSource) Defensive patterns
Strategy: fallback
Validate before calling
// verify sources before attempting the legacy fallback
for _, src := range []string{primarySource, githubSkillsSource} {
resp, err := http.Head(src)
if err != nil || resp.StatusCode >= 400 {
return fmt.Errorf("skills source unreachable: %s", src)
}
}
// unauthenticated GitHub requests are rate limited; provide credentials in CI Type guard
func fallbackInstallOK(r *selfupdate.NpmResult) bool { return r != nil && r.Err == nil } Try / catch
res := SyncSkills(opts)
if res != nil && res.Err != nil && strings.HasPrefix(res.Err.Error(), "separate skills sync failed") {
for _, reason := range strings.Split(res.Detail, "\n") {
log.Printf("sync failure reason: %s", reason) // fix each underlying cause
}
// retry after restoring network/auth to the sources
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- archive install failed: %s
- annotated_csv did not parse into the rows the server reporte
- npm install timed out after %s
- skills update timed out after %s
- suite skills sync failed: %s
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/4465ac309668c1bd.
Report an issue: GitHub.