{"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":719,"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":701,"sourceCodeEnd":737,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/skill.go#L701-L737","documentation":"fetchBytes enforces a 10MB size cap on skill sources by reading at most maxSkillDownloadBytes+1 bytes; if more than maxSkillDownloadBytes bytes arrive, it aborts with 'skill source too large (limit 10MB)'. This protects the workspace from oversized downloads.","triggerScenarios":"Downloading a repo zip (codeload) or direct-link file whose uncompressed-but-transferred body exceeds 10MB — e.g. a large monorepo zip or a release asset over the cap.","commonSituations":"Installing a skill from a repository that contains large binaries/history artifacts inflating the zip; a release asset (e.g. containing images or datasets) over 10MB; a self-hosted zip that is simply too big.","solutions":["Point at a smaller source: a subdirectory tree URL containing only the skill instead of the whole repo","Use a direct link to the individual SKILL.md (raw.githubusercontent.com) or a slim release asset","Trim large files from the source repo/release and retry","If the source is legitimately needed in full, the 10MB limit is fixed at maxSkillDownloadBytes in kernel/util/skill.go — self-host a trimmed archive instead"],"exampleFix":"// before\nInstallSkill(\"https://github.com/owner/huge-monorepo\") // zip > 10MB\n// after\nInstallSkill(\"https://github.com/owner/huge-monorepo/tree/main/skills/my-skill\")","handlingStrategy":"validation","validationCode":"const r = await fetch(downloadUrl, { method: \"HEAD\" })\nconst size = Number(r.headers.get(\"content-length\") || 0)\nif (size > 10 * 1024 * 1024) throw new Error(`source exceeds 10MB limit (${size} bytes)`)","typeGuard":null,"tryCatchPattern":"try {\n  await installSkill(src)\n} catch (e) {\n  if (String(e).includes(\"skill source too large\")) {\n    showHint(\"Use a subdirectory tree URL or a direct SKILL.md link instead of the full repo\")\n  }\n}","preventionTips":["Install from skill subdirectories, not whole repos with large binaries","Prefer raw.githubusercontent.com links for single-file skills","HEAD-check Content-Length before installing when the source size is unknown"],"tags":["download","size-limit","validation"],"backgroundTag":"payload-too-large","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}