larksuite/cli · error

suite skills sync failed: %s

Error message

suite skills sync failed: %s

What it means

SyncSkills aggregates the per-source failure reasons collected while trying every configured skills source. When the target layout is LayoutSuite and no source succeeded, it returns a SyncResult with Action="failed" and this error joining all reasons with "; " (the multiline breakdown is in SyncResult.Detail). It is a top-level aggregate, not a root cause: read the embedded per-source reasons to find the underlying index-fetch or sync-layout failure.

Source

Thrown at internal/skillscheck/sync.go:340

			LocalSkills:    localOfficial,
			PreviousState:  previous,
			StateReadable:  readable,
			Force:          opts.Force,
		})
		fallbackPlan = &plan

		if syncErr := syncLayout(opts.Runner, source, targetLayout, plan, installed); syncErr != nil {
			reasons = append(reasons, source+": "+syncErr.Error())
			continue
		}
		return finishSync(opts, targetLayout, plan, "", "", false)
	}

	if targetLayout == LayoutSuite {
		return &SyncResult{
			Action: "failed",
			Layout: targetLayout,
			Err:    fmt.Errorf("suite skills sync failed: %s", strings.Join(reasons, "; ")),
			Detail: strings.Join(reasons, "\n"),
			Force:  opts.Force,
		}
	}

	return fallbackSeparate(opts, previous, readable, localOfficial, installed, fallbackPlan, reasons)
}

func fetchOfficialSkills(runner SkillsRunner, source string) ([]string, error) {
	result := runner.FetchSkillsIndex(source)
	if result == nil || result.Err != nil {
		return nil, fmt.Errorf("index request failed: %s", resultDetail(result))
	}
	official, err := ParseOfficialSkillsIndexJSON(result.Stdout.String())
	if err != nil {
		return nil, fmt.Errorf("invalid v0.2 index: %w", err)
	}
	if len(official) == 0 {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Read SyncResult.Detail (or the joined Err message) for the per-source reason and fix the underlying failure for each source
  2. Verify network connectivity and that the skills index source URL is reachable (curl the index URL)
  3. Check that the remote publishes a valid non-empty v0.2 skills index (see errors 426-428 for specifics)
  4. Inspect the SkillsRunner implementation and its SkillsSources() configuration for misconfiguration
  5. Re-run with opts.Force or after fixing state if local state corruption contributes

Example fix

// before: opaque aggregate
res := SyncSkills(opts)
if res.Action == "failed" { log.Println(res.Err) }
// after: surface per-source breakdown
res := SyncSkills(opts)
if res.Action == "failed" {
    for _, line := range strings.Split(res.Detail, "\n") {
        log.Printf("source failure: %s", line)
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if opts.Runner == nil { return errors.New("runner must be set before SyncSkills") }
for _, s := range opts.Runner.SkillsSources() {
    if !isReachable(s) { log.Printf("source unreachable before sync: %s", s) }
}

Try / catch

res := SyncSkills(opts)
if res.Action == "failed" && res.Err != nil {
    var syncErr = res.Err
    // per-source breakdown is in res.Detail
    for _, reason := range strings.Split(res.Detail, "\n") {
        log.Printf("sync source failed: %s", reason)
    }
    if strings.Contains(syncErr.Error(), "suite skills sync failed") {
        // network/index problem, safe to retry after connectivity check
    }
}

Prevention

When it happens

Trigger: Calling SyncSkills with target layout LayoutSuite when every source in Runner.SkillsSources() fails either fetchOfficialSkills (index request failed / invalid index / empty index) or syncLayout.

Common situations: No network access or the skills index host is unreachable; the configured source URL is wrong; the remote serves a non-v0.2 or malformed index JSON; the runner's skills command is broken so syncLayout fails everywhere; a proxy/firewall blocks the index endpoint.

Related errors


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