siyuan-note/siyuan · critical

write box conf [ ] failed

Error message

write box conf [%s] failed: %w

What it means

saveConf0 writes the serialized conf.json through filelock.WriteFile; on failure it reports a filesystem-fatal error and returns this wrapped error. It means the notebook configuration could not be persisted to <DataDir>/<boxID>/.siyuan/conf.json.

Solutions

  1. Check permissions/ownership of <DataDir>/<boxID>/.siyuan/conf.json and make it writable by the process user
  2. Free disk space if the volume is full
  3. Close other programs (sync clients, editors) holding a lock on conf.json
  4. Check the kernel log for the ReportFileSysFatalError detail to identify the exact OS error
  5. Restart SiYuan after fixing the filesystem to re-attempt persistence

Example fix

// before (Linux)
ls -l conf.json  # owned by root, mode 0644
// after
sudo chown $USER:$USER conf.json && chmod u+w conf.json
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: check the target file is writable first
p := filepath.Join(util.DataDir, box.ID, ".siyuan/conf.json")
if f, err := os.OpenFile(p, os.O_WRONLY, 0); err != nil {
    return fmt.Errorf("conf.json not writable: %w", err)
} else {
    f.Close()
}

Try / catch

if err := box.SaveConf(conf); err != nil {
    if strings.Contains(err.Error(), "write box conf") {
        // inspect kernel log ReportFileSysFatalError detail, fix fs, restart
    }
}

Prevention

When it happens

Trigger: Calling Box.SaveConf when filelock.WriteFile fails: read-only filesystem, permission denied on the existing conf.json, disk full, file locked by another process, or antivirus blocking the write.

Common situations: conf.json owned by another user after running SiYuan as root/admin once; OneDrive/Dropbox sync locking the file on Windows; disk quota exceeded; workspace folder moved or unmounted while running.

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/5e01fd2c2b1f3d64. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/box.go:384

	}
	if needWriteNotebookCryptBackup(boxID, boxConf.BoxCrypt) {
		return writeNotebookCryptBackup(boxID, boxConf.BoxCrypt)
	}
	return nil
}

func (box *Box) saveConf0(data []byte) error {
	if !ast.IsNodeIDPattern(box.ID) {
		return fmt.Errorf("invalid box ID [%s]", box.ID)
	}

	confPath := filepath.Join(util.DataDir, box.ID, ".siyuan/conf.json")
	if err := os.MkdirAll(filepath.Join(util.DataDir, box.ID, ".siyuan"), 0755); err != nil {
		return fmt.Errorf("mkdir box conf dir failed: %w", err)
	}
	if err := filelock.WriteFile(confPath, data); err != nil {
		util.ReportFileSysFatalError(err)
		return fmt.Errorf("write box conf [%s] failed: %w", confPath, err)
	}
	invalidateEncryptedPublishAccessCache()
	return nil
}

// validateBoxPath 校验 box 内相对路径,拒绝 .. 和绝对路径,确保最终路径在 <DataDir>/<boxID>/ 内。
func (box *Box) validateBoxPath(p string) (string, error) {
	return filesys.ValidateBoxRelativePath(box.ID, p)
}

func (box *Box) Ls(p string) (ret []*FileInfo, totals int, err error) {
	if _, err = box.validateBoxPath(p); err != nil {
		return
	}
	boxLocalPath := filepath.Join(util.DataDir, box.ID)
	if before, ok := strings.CutSuffix(p, ".sy"); ok {
		dir := before
		absDir := filepath.Join(boxLocalPath, dir)

View on GitHub (pinned to 9f775e8a12)