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
- 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.
- Inspect the file with `cat <config-dir>/skills-state.json | jq .` to find the JSON syntax or type error and fix it manually.
- Match the error with errors.Is(err, skillscheck.ErrUnreadableState) and fall back to defaults instead of aborting.
- 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
- Never hand-edit skills-state.json; let the CLI regenerate it
- Delete the file instead of repairing it when the CLI reports unreadable state
- Ensure the CLI is not killed mid-write (avoid SIGKILL during state updates)
- Check disk health/filesystem errors if corruption recurs
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
- lark-cli stdout was not JSON: {snippet}
- lark-cli returned a non-object JSON payload
- %s must be a boolean
- %s must be an integer
- %s must be a number
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/ae6c47e30170b752.
Report an issue: GitHub.