{"record":{"id":"eb4ce427fd462101","repo":"larksuite/cli","slug":"w-v-eb4ce4","errorCode":null,"errorMessage":"%w: %v","messagePattern":"%w: %v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skillscheck/state.go","lineNumber":50,"sourceCode":"\tUpdatedAt             string   `json:\"updated_at\"`\n}\n\nfunc statePath() string {\n\treturn filepath.Join(core.GetBaseConfigDir(), stateFile)\n}\n\nfunc ReadState() (*SkillsState, bool, error) {\n\tdata, err := vfs.ReadFile(statePath())\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, false, nil\n\t\t}\n\t\treturn nil, false, err\n\t}\n\n\tvar raw map[string]interface{}\n\tif err := json.Unmarshal(data, &raw); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"%w: %v\", ErrUnreadableState, err)\n\t}\n\n\tvar state SkillsState\n\tif err := json.Unmarshal(data, &state); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"%w: %v\", ErrUnreadableState, err)\n\t}\n\treturn &state, true, nil\n}\n\nfunc WriteState(state SkillsState) error {\n\tstate.ensureNonNilSlices()\n\n\tif err := vfs.MkdirAll(core.GetBaseConfigDir(), 0o700); err != nil {\n\t\treturn err\n\t}\n\tdata, err := json.MarshalIndent(state, \"\", \"  \")\n\tif err != nil {\n\t\treturn err","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/skillscheck/state.go#L32-L68","documentation":"ReadState in internal/skillscheck/state.go wraps ErrUnreadableState when the persisted skills state file exists but cannot be parsed. It first tries a generic map unmarshal (line 50); if the file is not a JSON object at all, this error is returned with the json.Unmarshal cause via %w/%v. It signals corrupted or non-JSON state data, not a missing file (missing files are handled upstream).","triggerScenarios":"Calling ReadState when the state file contains malformed JSON (e.g. truncated write, binary data, or a JSON array/string instead of an object), so the first json.Unmarshal into map[string]interface{} fails.","commonSituations":"Disk full or crash mid-write leaving a truncated state file; a user hand-edited the state file into invalid JSON; the file was replaced by another tool writing a non-object JSON value; encoding mismatch (e.g. UTF-16 file saved by an editor).","solutions":["Inspect the state file and fix or remove invalid JSON characters; deleting the corrupt file lets skillscheck regenerate it","Validate the file with `jq . <state-file>` to pinpoint the syntax error","Restore the file from backup or let WriteState recreate it on the next successful run","If writes are being truncated, check disk space and ensure writes complete atomically"],"exampleFix":"// before\n$ cat ~/.lark/skills-state.json\n{\"lastRun\":\"2026-09-04\" // truncated\n// after (valid object)\n{\"lastRun\":\"2026-09-04\",\"skills\":[]}","handlingStrategy":"try-catch","validationCode":"// before calling ReadState\nif data, err := os.ReadFile(statePath); err == nil {\n    if !json.Valid(data) {\n        // state file is corrupt; remove or repair before ReadState\n        os.Remove(statePath)\n    }\n}","typeGuard":"func isUnreadableState(err error) bool {\n    return errors.Is(err, skillscheck.ErrUnreadableState)\n}","tryCatchPattern":"state, ok, err := skillscheck.ReadState(path)\nif err != nil {\n    if errors.Is(err, skillscheck.ErrUnreadableState) {\n        // corrupt file: log and fall back to fresh state\n        os.Remove(path)\n        state, ok, err = skillscheck.ReadState(path)\n    }\n    if err != nil { return err }\n}","preventionTips":["Write the state file atomically (temp file + rename) so crashes never leave truncated JSON","Never hand-edit the state file; regenerate it instead","Monitor disk space on the host holding the state file","Periodically validate the file with `jq empty` in health checks"],"tags":["json","state-file","corruption"],"backgroundTag":"state-file-unreadable","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"}