siyuan-note/siyuan · error

failed to write file

Error message

failed to write file: %w

What it means

filelock.WriteFile failed after the parent directories were successfully created while servicing siyuan.storage.put. The wrapped error (%w) is the underlying cause — typically disk full, permission denied on the target file, or the target path existing as a directory. The write is performed under SiYuan's file lock to avoid concurrent-write corruption.

Solutions

  1. Inspect the wrapped OS error in the rejection for the concrete cause
  2. Free disk space if the error indicates ENOSPC, and confirm workspace writability
  3. Ensure the target path is not an existing directory; remove it or choose a different filename
  4. Retry the put — transient locks from sync/AV tools often clear within seconds

Example fix

// before
await siyuan.storage.put("cache", text); // "cache" is an existing directory
// after
await siyuan.storage.put("cache/page.html", text); // write into a file path instead
Defensive patterns

Strategy: retry

Validate before calling

if (!path || path.endsWith("/")) throw new TypeError("target must be a file path, not a directory");

Type guard

const isFilePath = (p) => typeof p === "string" && p.length > 0 && !p.endsWith("/");

Try / catch

try { await siyuan.storage.put(path, content); } catch (e) { if (String(e.message).includes("failed to write file")) { await delay(500); return siyuan.storage.put(path, content); } throw e; }

Prevention

When it happens

Trigger: The workspace disk is full or quota-exhausted; the target file is read-only or owned by another user; the target path resolves to an existing directory; antivirus/backup tools hold the file during the locked write on Windows.

Common situations: Plugins writing large blobs that fill the workspace volume; files made read-only by sync clients (OneDrive/iCloud placeholders); a previously created directory occupying the exact target path.

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/0d8deb3fc9dbfb2f. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/api_storage.go:282

						if lo.IsNil(err) {
							if resolveErr := resolve(result); resolveErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.put resolve: %v", p.Name, resolveErr)
							}
						} else {
							if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
								logging.LogErrorf("[plugin:%s] siyuan.storage.put reject: %v", p.Name, rejectErr)
							}
						}
						return
					}, nil)
				}()

				if mkdirErr := os.MkdirAll(filepath.Dir(abs), 0755); mkdirErr != nil {
					err = fmt.Errorf("failed to make directory: %w", mkdirErr)
					return
				}
				if writeErr := filelock.WriteFile(abs, []byte(content)); writeErr != nil {
					err = fmt.Errorf("failed to write file: %w", writeErr)
					return
				}
				return
			}()

			return
		}, func(rt *goja.Runtime, result any, err error) {
			if !lo.IsNil(err) {
				if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
					logging.LogErrorf("[plugin:%s] siyuan.storage.put reject: %v", p.Name, rejectErr)
				}
			}
		})
		if runErr != nil {
			logging.LogErrorf("[plugin:%s] siyuan.storage.put worker run: %v", p.Name, runErr)
			if rejectErr := reject(rt.NewGoError(runErr)); rejectErr != nil {
				logging.LogErrorf("[plugin:%s] siyuan.storage.put reject: %v", p.Name, rejectErr)
			}

View on GitHub (pinned to 9f775e8a12)