larksuite/cli · warning

skills state is unreadable

Error message

skills state is unreadable

What it means

ErrUnreadableState is a sentinel error returned by ReadState in internal/skillscheck when the persisted skills-state.json file in the CLI config directory cannot be decoded as JSON, either as a generic object or as the SkillsState schema. It wraps the underlying json.Unmarshal error with %w so callers can match it with errors.Is. It signals a corrupt or schema-mismatched local state file, not an API problem.

Source

Thrown at internal/skillscheck/state.go:22

package skillscheck

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/fs"
	"path/filepath"

	"github.com/larksuite/cli/internal/core"
	"github.com/larksuite/cli/internal/validate"
	"github.com/larksuite/cli/internal/vfs"
)

const (
	stateFile = "skills-state.json"
)

var ErrUnreadableState = errors.New("skills state is unreadable")

type SkillsState struct {
	Version               string   `json:"version"`
	Layout                Layout   `json:"layout,omitempty"`
	OfficialSkills        []string `json:"official_skills"`
	OfficialSkillsUnknown bool     `json:"official_skills_unknown,omitempty"`
	UpdatedSkills         []string `json:"updated_skills"`
	AddedOfficialSkills   []string `json:"added_official_skills"`
	SkippedDeletedSkills  []string `json:"skipped_deleted_skills"`
	UpdatedAt             string   `json:"updated_at"`
}

func statePath() string {
	return filepath.Join(core.GetBaseConfigDir(), stateFile)
}

func ReadState() (*SkillsState, bool, error) {
	data, err := vfs.ReadFile(statePath())

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Delete the corrupt skills-state.json file in the CLI base config directory (core.GetBaseConfigDir()) and rerun the command; ReadState treats a missing file as 'no state' and the state is regenerated.
  2. Inspect the file with `cat <config-dir>/skills-state.json | jq .` to find the JSON syntax or type error and fix it manually.
  3. Match the error with errors.Is(err, skillscheck.ErrUnreadableState) and fall back to defaults instead of aborting.
  4. If corruption recurs, check disk health and ensure the CLI process is not being killed mid-write.

Example fix

// before
state, found, err := skillscheck.ReadState()
if err != nil { log.Fatal(err) }
// after
state, found, err := skillscheck.ReadState()
if errors.Is(err, skillscheck.ErrUnreadableState) {
    // recover by ignoring corrupt state
    state, found = nil, false
} else if err != nil {
    log.Fatal(err)
}
Defensive patterns

Strategy: try-catch

Type guard

func stateExists(p string) bool { b, err := os.ReadFile(p); return err == nil && json.Valid(b) }

Try / catch

state, found, err := skillscheck.ReadState()
if errors.Is(err, skillscheck.ErrUnreadableState) {
    // corrupt state: proceed without it
    state, found = nil, false
} else if err != nil {
    return err
}

Prevention

When it happens

Trigger: ReadState parses skills-state.json and json.Unmarshal fails: (1) the file is corrupt/truncated (interrupted write, disk issue) or contains invalid JSON; (2) the file parses as JSON but does not match SkillsState — e.g. a field like version or official_skills has the wrong JSON type (string vs array).

Common situations: Users hand-edit ~/.config/lark-cli/skills-state.json (or the platform config dir) and break the JSON; a crash or SIGKILL during WriteState left a partial file; an older or newer CLI version wrote a state schema whose field types changed, breaking unmarshal.

Related errors


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