siyuan-note/siyuan · error
write file failed
Error message
write file failed: %s
What it means
After creating the import directory, WebFetch writes the downloaded bytes with os.WriteFile(filePath, body, 0644); any write failure (permission denied, disk full, invalid filename path) is wrapped as 'write file failed: <cause>'. The download itself succeeded; persisting it failed.
Solutions
- Read the wrapped cause after 'write file failed: ' (ENOSPC vs EACCES vs ENAMETOOLONG)
- Free disk space or raise the quota on the temp/workspace volume
- Verify the kernel process can create files in <TempDir>/import (test with touch)
- Shorten or sanitize the source URL so extractFilename produces a shorter filename
Example fix
// before // ENOSPC: disk full, silent until this error $ df -h /tmp # check free space // after $ df -h /tmp && du -sh <workspace>/* # identify and clear space, then retry
Defensive patterns
Strategy: try-catch
Validate before calling
importDir := filepath.Join(TempDir, "import")
if f, err := os.CreateTemp(importDir, "probe-*"); err != nil {
return errors.New("temp import dir not writable: " + err.Error())
} else {
f.Close(); os.Remove(f.Name())
} Try / catch
_, err := WebFetch(url, format)
if err != nil && strings.Contains(err.Error(), "write file failed") {
// check ENOSPC (free space/quota), EACCES (permissions), ENAMETOOLONG (shorten URL)
} Prevention
- Monitor free space and inode/quota limits on the temp volume
- Keep source URLs reasonably short — extractFilename derives the saved name from them
- Verify write access to <TempDir>/import after user or deployment changes
- Account for security software that may block writes of downloaded file types
When it happens
Trigger: The temp volume is full or read-only; the extractFilename-derived name resolves to a path that cannot be created; an antivirus or OS policy blocks writing the file type; permission changed between mkdir and write.
Common situations: Disk quota exceeded on the workspace volume; fetching files whose derived names are unusually long (exceeding filesystem NAME_MAX on some systems); SELinux/AppArmor denials in hardened deployments.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- create import dir failed
- enable encrypted notebook failed: failed to persist key…
- failed to persist key backup
- write AI editor actions failed
- write data [ ] failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/42e1f9b2a75edd5d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/webfetch.go:85
}
if resp.ContentLength > maxReadBytes {
return "", errors.New("response too large")
}
body, err := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))
if err != nil {
return "", errors.New("read body failed: " + err.Error())
}
if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "text/plain") {
importDir := filepath.Join(TempDir, "import")
if merr := os.MkdirAll(importDir, 0755); merr != nil {
return "", errors.New("create import dir failed: " + merr.Error())
}
filename := extractFilename(rawURL, contentType)
filePath := filepath.Join(importDir, filename)
if werr := os.WriteFile(filePath, body, 0644); werr != nil {
return "", errors.New("write file failed: " + werr.Error())
}
return fmt.Sprintf("Saved to: %s (%d bytes)", filePath, len(body)), nil
}
htmlStr := string(body)
isHTML := strings.HasPrefix(contentType, "text/html")
if !isHTML {
return truncateRunes(htmlStr, maxWebFetchChars), nil
}
if htmlStr == "" {
return "", nil
}
engine := NewLute()
var result string
switch format {View on GitHub (pinned to 9f775e8a12)