{"record":{"id":"b49bfbc566e7ba4c","repo":"larksuite/cli","slug":"suite-skills-sync-failed-s","errorCode":null,"errorMessage":"suite skills sync failed: %s","messagePattern":"suite skills sync failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skillscheck/sync.go","lineNumber":340,"sourceCode":"\t\t\tLocalSkills:    localOfficial,\n\t\t\tPreviousState:  previous,\n\t\t\tStateReadable:  readable,\n\t\t\tForce:          opts.Force,\n\t\t})\n\t\tfallbackPlan = &plan\n\n\t\tif syncErr := syncLayout(opts.Runner, source, targetLayout, plan, installed); syncErr != nil {\n\t\t\treasons = append(reasons, source+\": \"+syncErr.Error())\n\t\t\tcontinue\n\t\t}\n\t\treturn finishSync(opts, targetLayout, plan, \"\", \"\", false)\n\t}\n\n\tif targetLayout == LayoutSuite {\n\t\treturn &SyncResult{\n\t\t\tAction: \"failed\",\n\t\t\tLayout: targetLayout,\n\t\t\tErr:    fmt.Errorf(\"suite 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\n\treturn fallbackSeparate(opts, previous, readable, localOfficial, installed, fallbackPlan, reasons)\n}\n\nfunc fetchOfficialSkills(runner SkillsRunner, source string) ([]string, error) {\n\tresult := runner.FetchSkillsIndex(source)\n\tif result == nil || result.Err != nil {\n\t\treturn nil, fmt.Errorf(\"index request failed: %s\", resultDetail(result))\n\t}\n\tofficial, err := ParseOfficialSkillsIndexJSON(result.Stdout.String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid v0.2 index: %w\", err)\n\t}\n\tif len(official) == 0 {","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/skillscheck/sync.go#L322-L358","documentation":"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.","triggerScenarios":"Calling SyncSkills with target layout LayoutSuite when every source in Runner.SkillsSources() fails either fetchOfficialSkills (index request failed / invalid index / empty index) or syncLayout.","commonSituations":"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.","solutions":["Read SyncResult.Detail (or the joined Err message) for the per-source reason and fix the underlying failure for each source","Verify network connectivity and that the skills index source URL is reachable (curl the index URL)","Check that the remote publishes a valid non-empty v0.2 skills index (see errors 426-428 for specifics)","Inspect the SkillsRunner implementation and its SkillsSources() configuration for misconfiguration","Re-run with opts.Force or after fixing state if local state corruption contributes"],"exampleFix":"// before: opaque aggregate\nres := SyncSkills(opts)\nif res.Action == \"failed\" { log.Println(res.Err) }\n// after: surface per-source breakdown\nres := SyncSkills(opts)\nif res.Action == \"failed\" {\n    for _, line := range strings.Split(res.Detail, \"\\n\") {\n        log.Printf(\"source failure: %s\", line)\n    }\n}","handlingStrategy":"try-catch","validationCode":"if opts.Runner == nil { return errors.New(\"runner must be set before SyncSkills\") }\nfor _, s := range opts.Runner.SkillsSources() {\n    if !isReachable(s) { log.Printf(\"source unreachable before sync: %s\", s) }\n}","typeGuard":null,"tryCatchPattern":"res := SyncSkills(opts)\nif res.Action == \"failed\" && res.Err != nil {\n    var syncErr = res.Err\n    // per-source breakdown is in res.Detail\n    for _, reason := range strings.Split(res.Detail, \"\\n\") {\n        log.Printf(\"sync source failed: %s\", reason)\n    }\n    if strings.Contains(syncErr.Error(), \"suite skills sync failed\") {\n        // network/index problem, safe to retry after connectivity check\n    }\n}","preventionTips":["Check network/proxy reachability of all configured sources before syncing","Keep SkillsSources() configured with a healthy production index URL","Inspect SyncResult.Detail, not just Err, when a suite sync fails","Keep the skills CLI updated so index schema and sync code stay compatible"],"tags":["go","skills-sync","aggregate-error","network"],"backgroundTag":"skills-sync-source-failure","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"}