siyuan-note/siyuan · error
skill source too large (limit 10MB)
Error message
skill source too large (limit 10MB)
What it means
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.
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
Example fix
// before
InstallSkill("https://github.com/owner/huge-monorepo") // zip > 10MB
// after
InstallSkill("https://github.com/owner/huge-monorepo/tree/main/skills/my-skill") Defensive patterns
Strategy: validation
Validate before calling
const r = await fetch(downloadUrl, { method: "HEAD" })
const size = Number(r.headers.get("content-length") || 0)
if (size > 10 * 1024 * 1024) throw new Error(`source exceeds 10MB limit (${size} bytes)`) Try / catch
try {
await installSkill(src)
} catch (e) {
if (String(e).includes("skill source too large")) {
showHint("Use a subdirectory tree URL or a direct SKILL.md link instead of the full repo")
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/4e9b5e1617762bd5.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/skill.go:719
// fetchBytes 执行带大小限制的 GET
func fetchBytes(rawURL string) (data []byte, contentType string, err error) {
resp, err := httpclient.NewBrowserRequest().Get(rawURL)
if err != nil {
return nil, "", errors.New("download failed: " + err.Error())
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return nil, "", fmt.Errorf("download failed: HTTP %d", resp.StatusCode)
}
contentType = resp.Header.Get("Content-Type")
body, err := io.ReadAll(io.LimitReader(resp.Body, maxSkillDownloadBytes+1))
if err != nil {
return nil, "", errors.New("read body failed: " + err.Error())
}
if len(body) > maxSkillDownloadBytes {
return nil, "", errors.New("skill source too large (limit 10MB)")
}
return body, contentType, nil
}
// installFromZip 解压 zip 并安装其中的 skill
func installFromZip(data []byte) (*InstallSkillResult, error) {
tmpRoot := filepath.Join(TempDir, "ai", "skill-install", gulu.Rand.String(7))
if err := os.MkdirAll(tmpRoot, 0755); err != nil {
return nil, err
}
defer os.RemoveAll(tmpRoot)
zipPath := filepath.Join(tmpRoot, "src.zip")
if err := os.WriteFile(zipPath, data, 0644); err != nil {
return nil, err
}
unzipDir := filepath.Join(tmpRoot, "unzip")
if err := os.MkdirAll(unzipDir, 0755); err != nil {View on GitHub (pinned to 9f775e8a12)