{"record":{"id":"4e9b5e1617762bd5","repo":"siyuan-note/siyuan","slug":"skill-source-too-large-limit-10mb","errorCode":null,"errorMessage":"skill source too large (limit 10MB)","messagePattern":"skill source too large \\(limit 10MB\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/skill.go","lineNumber":417,"sourceCode":"// fetchBytes 执行带大小限制的 GET\nfunc fetchBytes(rawURL string) (data []byte, contentType string, err error) {\n\tresp, err := httpclient.NewBrowserRequest().Get(rawURL)\n\tif err != nil {\n\t\treturn nil, \"\", errors.New(\"download failed: \" + err.Error())\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode >= 400 {\n\t\treturn nil, \"\", fmt.Errorf(\"download failed: HTTP %d\", resp.StatusCode)\n\t}\n\n\tcontentType = resp.Header.Get(\"Content-Type\")\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxSkillDownloadBytes+1))\n\tif err != nil {\n\t\treturn nil, \"\", errors.New(\"read body failed: \" + err.Error())\n\t}\n\tif len(body) > maxSkillDownloadBytes {\n\t\treturn nil, \"\", errors.New(\"skill source too large (limit 10MB)\")\n\t}\n\treturn body, contentType, nil\n}\n\n// installFromZip 解压 zip 并安装其中的 skill\nfunc installFromZip(data []byte) (*InstallSkillResult, error) {\n\ttmpRoot := filepath.Join(TempDir, \"ai\", \"skill-install\", gulu.Rand.String(7))\n\tif err := os.MkdirAll(tmpRoot, 0755); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer os.RemoveAll(tmpRoot)\n\n\tzipPath := filepath.Join(tmpRoot, \"src.zip\")\n\tif err := os.WriteFile(zipPath, data, 0644); err != nil {\n\t\treturn nil, err\n\t}\n\tunzipDir := filepath.Join(tmpRoot, \"unzip\")\n\tif err := os.MkdirAll(unzipDir, 0755); err != nil {","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/skill.go#L399-L435","documentation":"Thrown by fetchBytes when the downloaded body exceeds maxSkillDownloadBytes (10 MiB). The reader deliberately reads one extra byte to detect the overflow, then rejects the payload. This caps skill source size to protect memory and disk.","triggerScenarios":"A zip archive or SKILL.md larger than 10 MiB; a URL that returns an unexpectedly large file (e.g. a full repository dump, a binary asset, or an HTML page with embedded data).","commonSituations":"Targeting a repo that bundles large assets (images, model files); accidentally pointing at a release containing big binaries; a monorepo whose zip is huge.","solutions":["Install a subdirectory skill via the tree/<branch>/<path> URL to reduce payload size.","Use a raw SKILL.md link instead of the full-repo zip.","Trim large assets out of the skill repository, or host a pre-built minimal zip.","If the limit must rise, raise maxSkillDownloadBytes and rebuild the kernel (requires code change)."],"exampleFix":"// before — downloads the entire large repo as zip\nutil.InstallSkill(\"owner/big-repo\")\n\n// after — install only the skill subdirectory\nutil.InstallSkill(\"https://github.com/owner/big-repo/tree/main/skills/my-skill\")","handlingStrategy":"validation","validationCode":"// steer users to narrower sources for large repos\nif strings.HasSuffix(src, \".git\") || looksLikeFullRepo(src {\n    // suggest the tree/<branch>/<path> form or a raw SKILL.md URL\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep skill repositories small; strip large binaries and assets.","Use raw SKILL.md links or tree/<branch>/<path> URLs to install a single skill.","Host a purpose-built minimal zip if the full repo is unavoidably large."],"tags":["skill-management","network","size-limit"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}