larksuite/cli · error

local skills list failed

Error message

local skills list failed

What it means

listInstalledSkills tries two local discovery paths: the runner's global skills JSON listing (parseInstalledSkillsJSON) and its plain-text listing (ParseSkillsList). If both fail or yield unparseable output, it returns this fixed-message error and SyncSkills aborts with Action="failed". It means the CLI cannot determine which skills are installed locally, so a safe sync plan cannot be computed.

Source

Thrown at internal/skillscheck/sync.go:383

	jsonResult := runner.ListGlobalSkillsJSON()
	if jsonResult != nil && jsonResult.Err == nil {
		if installed, err := parseInstalledSkillsJSON(jsonResult.Stdout.String()); err == nil {
			return installed, nil
		}
	}

	textResult := runner.ListGlobalSkills()
	if textResult != nil && textResult.Err == nil {
		names := ParseSkillsList(textResult.Stdout.String())
		if names != nil {
			installed := make([]installedSkill, 0, len(names))
			for _, name := range names {
				installed = append(installed, installedSkill{Name: name})
			}
			return installed, nil
		}
	}
	return nil, fmt.Errorf("local skills list failed")
}

func localOfficialSkills(installed []installedSkill, previous *SkillsState, readable bool) ([]string, error) {
	if !readable || previous == nil || EffectiveLayout(previous) == LayoutSeparate {
		names := make([]string, 0, len(installed))
		for _, skill := range installed {
			names = append(names, skill.Name)
		}
		return names, nil
	}

	for _, skill := range installed {
		if skill.Name != "lark-suite" {
			continue
		}
		if skill.Path == "" {
			return nil, fmt.Errorf("cannot inspect installed lark-suite: global skills JSON did not include its path")
		}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Run the underlying skills list command manually and check its stdout/stderr for the real failure
  2. Reinstall or update the skills CLI so its JSON output matches the expected schema
  3. Fix permissions/existence of the local skills installation directory
  4. Clear or repair corrupted local skills state, then retry the sync
  5. Check CLI version compatibility — a schema change in list output breaks both parse paths

Example fix

// before: both parse paths fail silently
installed, err := listInstalledSkills(runner) // err: local skills list failed
// after: capture raw outputs for diagnosis
jsonResult := runner.ListGlobalSkillsJSON()
if jsonResult == nil || jsonResult.Err != nil {
    log.Printf("JSON listing failed: %v (stdout=%q)", errString(jsonResult), rawOf(jsonResult))
}
installed, err := listInstalledSkills(runner)
Defensive patterns

Strategy: type-guard

Validate before calling

if jr := runner.ListGlobalSkillsJSON(); jr != nil && jr.Err == nil {
    if _, err := parseInstalledSkillsJSON(jr.Stdout.String()); err != nil {
        log.Printf("local JSON listing unparseable, falling back to text listing")
    }
}

Type guard

func localSkillsReadable(runner SkillsRunner) bool {
    if jr := runner.ListGlobalSkillsJSON(); jr != nil && jr.Err == nil {
        if _, err := parseInstalledSkillsJSON(jr.Stdout.String()); err == nil {
            return true
        }
    }
    if tr := runner.ListGlobalSkills(); tr != nil && tr.Err == nil {
        return ParseSkillsList(tr.Stdout.String()) != nil
    }
    return false
}

Try / catch

if !localSkillsReadable(runner) {
    // run the list command manually, capture stderr, fix CLI/version before syncing
    out, execErr := exec.Command("lark-cli", "skills", "list", "--json").CombinedOutput()
    return fmt.Errorf("local skills unreadable: %v (out=%s)", execErr, out)
}
installed, err := listInstalledSkills(runner)
if err != nil { return err }

Prevention

When it happens

Trigger: SyncSkills -> listInstalledSkills where ListGlobalSkillsJSON returns nil/Err or unparseable JSON AND ListGlobalSkills returns nil/Err or unparseable text output.

Common situations: The skills CLI binary is missing, broken, or an incompatible version; the local skills directory was deleted or has bad permissions; the JSON output format changed between CLI versions so the parser rejects it; a corrupted local state file; running in a sandbox where the CLI cannot execute.

Related errors


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