siyuan-note/siyuan · error

write file failed

Error message

write file failed: %s

What it means

os.WriteFile failed while saving a downloaded binary response to <workspace temp>/import/<filename>; the filename is derived by extractFilename from the URL and content type. The suffix carries the OS error - disk full, permission denied, or (on Windows) a locked existing file. Text responses never hit this path.

Solutions

  1. Free disk space on the temp volume and retry the download
  2. Clean stale files out of <workspace temp>/import
  3. Check permissions on the target file/directory and exclude the temp dir from AV real-time scanning on Windows

Example fix

// before: import dir filled by earlier downloads, disk full
util.HTTPRequest("GET", bigFileURL, nil, "")

// after: clean stale imports before large downloads
importDir := filepath.Join(util.TempDir, "import")
if entries, derr := os.ReadDir(importDir); derr == nil {
    for _, e := range entries {
        os.Remove(filepath.Join(importDir, e.Name()))
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if probe, perr := os.CreateTemp(filepath.Join(util.TempDir, "import"), "probe-*"); perr != nil {
    return perr // disk full or read-only: skip the binary download
} else {
    probe.Close()
    os.Remove(probe.Name())
}

Try / catch

if err != nil && strings.Contains(err.Error(), "write file failed") {
    cleanImportDir() // remove stale files, then retry the download once
}

Prevention

When it happens

Trigger: Disk fills exactly between the mkdir and the write; the import directory is read-only; an antivirus or indexer holds the target file open on Windows; a same-named file exists with restrictive permissions.

Common situations: Repeated large downloads filling the temp volume; leftover files from earlier runs with different ownership; AV interference on Windows.

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@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/a1a0ac43714cc6f7. Report an issue: GitHub.

Appendix: 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 afa823b6b4)