siyuan-note/siyuan · error
write file failed: %s
Error message
write file failed: %s
What it means
Returned at webfetch.go:86 when os.WriteFile(filePath, body, 0644) fails after the import directory was created successfully. The file payload was downloaded but could not be persisted. The %s is the OS write error.
Source
Thrown at kernel/util/webfetch.go:86
}
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 251596fc0d)
Solutions
- Free disk space on the target volume.
- Verify write permission and that no directory already uses the target filename.
- Retry — transient AV locks often clear on the second attempt.
- Check the filename produced by extractFilename for unexpected characters.
Defensive patterns
Strategy: validation
Validate before calling
// Best-effort free-space check on the import volume.
func importVolumeHasSpace() error {
dir := filepath.Join(util.TempDir, "import")
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
var stat syscall.Statfs_t
if err := syscall.Statfs(dir, &stat); err != nil {
return err
}
if uint64(stat.Bavail)*uint64(stat.Bsize) < uint64(10*1024*1024) {
return errors.New("less than 10 MiB free")
}
return nil
} Type guard
func isWriteFileFailed(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "write file failed:")
} Try / catch
out, err := util.WebFetch(raw, "markdown")
if err != nil && isWriteFileFailed(err) {
// often transient (AV lock on Windows) — retry once
out, err = util.WebFetch(raw, "markdown")
} Prevention
- Keep free disk space on the TempDir volume above the 10 MiB file cap.
- On Windows, exclude the SiYuan temp/import dir from AV real-time scanning.
- Avoid directory/file name collisions in the import dir.
When it happens
Trigger: Disk full at the moment of writing, permission denied on the target path, a directory already exists at the target filename, path-too-long, antivirus locking the file (Windows), or a read-only filesystem mounted between mkdir and write.
Common situations: Disk filling up during a large download, filename extracted by extractFilename colliding with an existing directory, security software scanning/locking newly written files.
Related errors
- write box conf [%s] failed: %w
- create dir for publishAccess.json [%s] failed: %s
- write publishAccess.json [%s] failed: %s
- write data [%s] failed: %s
- read image failed: %w
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/42e1f9b2a75edd5d.
Report an issue: GitHub.