siyuan-note/siyuan · error

write file failed:

Error message

write file failed: 

What it means

For binary (non-text) HTTP responses, HTTPRequest saves the already-read body bytes to <TempDir>/import/<filename> with os.WriteFile(filePath, respBody, 0644). If the file write fails, the error is wrapped as "write file failed: <cause>". The directory was created successfully, so failures here are usually about the specific file: permissions, disk space, or name collisions with unwritable entries.

Source

Thrown at kernel/util/httprequest.go:368

	if resp.ContentLength > maxReadBytes {
		return statusCode, contentType, "", errors.New("response too large")
	}

	respBody, rerr := io.ReadAll(io.LimitReader(resp.Body, maxReadBytes))
	if rerr != nil {
		return statusCode, contentType, "", errors.New("read body failed: " + rerr.Error())
	}

	// 二进制响应落盘,返回文件路径,供智能体按需进一步处理。
	if !isTextContentType(contentType) {
		importDir := filepath.Join(TempDir, "import")
		if merr := os.MkdirAll(importDir, 0755); merr != nil {
			return statusCode, contentType, "", errors.New("create import dir failed: " + merr.Error())
		}
		filename := extractFilename(rawURL, contentType)
		filePath := filepath.Join(importDir, filename)
		if werr := os.WriteFile(filePath, respBody, 0644); werr != nil {
			return statusCode, contentType, "", errors.New("write file failed: " + werr.Error())
		}
		return statusCode, contentType, fmt.Sprintf("Saved to: %s (%d bytes)", filePath, len(respBody)), nil
	}

	return statusCode, contentType, truncateRunes(string(respBody), maxHTTPRequestChars), nil
}

// isTextContentType 判断 Content-Type 是否为可直接展示给智能体的文本类响应。
// 覆盖 text/*、application/json、application/xml、application/*+json 等。
func isTextContentType(contentType string) bool {
	ct := strings.ToLower(strings.TrimSpace(strings.SplitN(contentType, ";", 2)[0]))
	if ct == "" {
		return false
	}
	if strings.HasPrefix(ct, "text/") {
		return true
	}
	switch ct {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Read the wrapped cause after "write file failed: " to distinguish ENOSPC (free disk space) from EACCES/EPERM (permissions)
  2. Free disk space on the volume holding the workspace temp directory if the cause is no-space
  3. Check ownership/permissions of the <TempDir>/import directory and remove conflicting entries with the same name
  4. Retry the request; if a specific server's filename is the problem, note the URL and inspect the extracted filename in <TempDir>/import

Example fix

// before
$ df -h <workspace>/temp   # check space
$ ls -la <workspace>/temp/import
// after: free space or fix perms
$ chmod u+w <workspace>/temp/import
$ rm -rf <workspace>/temp/import/<conflicting-dir>
Defensive patterns

Strategy: validation

Validate before calling

importDir := filepath.Join(util.TempDir, "import")
if stat, err := os.Stat(importDir); err != nil || !stat.IsDir() {
    return errors.New("import dir missing or not a directory")
}
// check writability
probe := filepath.Join(importDir, ".write-probe")
if err := os.WriteFile(probe, nil, 0644); err != nil {
    return fmt.Errorf("import dir not writable: %w", err)
}
os.Remove(probe)

Try / catch

status, ct, text, err := util.HTTPRequest("GET", binaryURL, nil, "")
if err != nil && strings.Contains(err.Error(), "write file failed") {
    if strings.Contains(err.Error(), "no space left") {
        return errors.New("free disk space before downloading binary responses")
    }
    return fmt.Errorf("check permissions on %s: %w", filepath.Join(util.TempDir, "import"), err)
}

Prevention

When it happens

Trigger: HTTPRequest() with a binary Content-Type where os.WriteFile to <TempDir>/import/<extracted filename> fails — disk full, permission denied, the target path exists as a directory, or a filename extracted from URL/Content-Type contains path-hostile content.

Common situations: Full disk after a large download, another process holding the file with restrictive locks/ACLs, an 'import' directory whose files were made read-only, or servers sending Content-Disposition/URLs that extract to unusual filenames.

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@8641553a1f (2026-09-11). Data as JSON: /api/errors/3b8c56f258fdbd5b. Report an issue: GitHub.