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

  1. Read the wrapped cause after 'write file failed: ' (ENOSPC vs EACCES vs ENAMETOOLONG)
  2. Free disk space or raise the quota on the temp/workspace volume
  3. Verify the kernel process can create files in <TempDir>/import (test with touch)
  4. 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

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


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)