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

  1. Read the joined reasons in Detail/message to see the primary and GitHub failure causes and fix the underlying network/auth issue first.
  2. Restore connectivity to github.com and the npm registry (check proxy/VPN/firewall settings) and retry the sync.
  3. 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.
  4. Check GitHub API rate limits (unauthenticated requests are limited) and retry later or provide credentials.
  5. 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

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


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/4465ac309668c1bd. Report an issue: GitHub.