{"record":{"id":"719c4b9448ad5edd","repo":"siyuan-note/siyuan","slug":"skill-resource-read-failed-s-s","errorCode":null,"errorMessage":"skill resource read failed: %s/%s","messagePattern":"skill resource read failed: (.+?)/(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/skill.go","lineNumber":385,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"skill resource escapes skill directory: %s\", resource)\n\t}\n\n\tinfo, err := os.Stat(realTarget)\n\tif err != nil || !info.Mode().IsRegular() {\n\t\treturn \"\", fmt.Errorf(\"skill resource is not a regular file: %s/%s\", skillName, resource)\n\t}\n\tif info.Size() > maxSkillResourceBytes {\n\t\treturn \"\", fmt.Errorf(\"skill resource exceeds the %d byte limit: %s/%s\", maxSkillResourceBytes, skillName, resource)\n\t}\n\n\tfile, err := os.Open(realTarget)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"skill resource not found: %s/%s\", skillName, resource)\n\t}\n\tdefer file.Close()\n\tdata, err := io.ReadAll(io.LimitReader(file, maxSkillResourceBytes+1))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"skill resource read failed: %s/%s\", skillName, resource)\n\t}\n\tif len(data) > maxSkillResourceBytes {\n\t\treturn \"\", fmt.Errorf(\"skill resource exceeds the %d byte limit: %s/%s\", maxSkillResourceBytes, skillName, resource)\n\t}\n\tif !utf8.Valid(data) {\n\t\treturn \"\", fmt.Errorf(\"skill resource is not valid UTF-8: %s/%s\", skillName, resource)\n\t}\n\treturn string(data), nil\n}\n\nfunc validateSkillName(name string) error {\n\tif name == \"\" || name == \".\" || name == \"..\" {\n\t\treturn fmt.Errorf(\"invalid skill name: %s\", name)\n\t}\n\tif strings.ContainsAny(name, `/\\`) {\n\t\treturn fmt.Errorf(\"invalid skill name: %s\", name)\n\t}\n\tdir := SkillsDir()","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/skill.go#L367-L403","documentation":"After opening the resource file, readSkillResource reads up to maxSkillResourceBytes+1 bytes with io.ReadAll; a non-EOF read error is reported as 'skill resource read failed'. This indicates an I/O problem while reading an already-open file, not a missing file or a size-limit rejection (those have distinct messages).","triggerScenarios":"LoadSkill -> readSkillResource: io.ReadAll on the opened resource file returns an error — disk I/O error, bad sectors, network-mounted file becoming unavailable mid-read, or a file descriptor issue.","commonSituations":"Failing or full disk hosting the workspace; NFS/SMB mount dropped while reading; storage device detached on mobile/external drives; extremely rare kernel/file-descriptor errors after Open succeeded.","solutions":["Check disk health and free space on the volume holding the workspace (dmesg / smartctl / df)","Retry the operation — transient I/O errors on network mounts often clear after remount","Verify the file is intact by reading it manually (cat/head) and restore from backup or re-download the skill if corrupt","Reinstall the skill (RemoveSkill then re-save/install) if the resource file is corrupted"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Go: sanity-check readability before the API\nf, err := os.Open(path)\nif err != nil { return err }\nb := make([]byte, 512)\n_, rerr := f.Read(b)\nf.Close()\nif rerr != nil && rerr != io.EOF { return rerr }","typeGuard":null,"tryCatchPattern":"if _, err := LoadSkill(skill, res); err != nil {\n    if strings.Contains(err.Error(), \"skill resource read failed\") {\n        time.Sleep(100 * time.Millisecond)\n        return retryLoad(skill, res, 1) // bounded retry for transient I/O\n    }\n    return err\n}","preventionTips":["Monitor disk health and free space on the workspace volume","Avoid storing skill resources on flaky network mounts","Restore corrupted skill directories from source control or backups"],"tags":["go","io","filesystem","skills"],"backgroundTag":"file-read-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}