siyuan-note/siyuan · error

write notebook crypto backup failed: %w

Error message

write notebook crypto backup failed: %w

What it means

saveNotebookCryptoBackup writes the JSON backup with atomicWriteFile after creating the directory; this error wraps a failed atomic write. The backup file (e.g. at the data crypto backup path) could not be written, so the on-disk recovery copy is missing or stale even though Conf in memory was already updated. Encrypted-notebook recovery depends on this file, so it should be resolved immediately.

Source

Thrown at kernel/model/crypto.go:407

		Conf.m.Unlock()
		return errors.New("cannot save incomplete notebook crypto configuration")
	}
	Conf.NotebookCrypto.Spec = nc.Spec
	Conf.NotebookCrypto.BackupID = nc.BackupID
	Conf.NotebookCrypto.CreatedAt = nc.CreatedAt
	Conf.NotebookCrypto.Checksum = nc.Checksum
	Conf.NotebookCrypto.KEKMAC = nc.KEKMAC // 保持 Conf 与备份文件的 KEKMAC 一致
	Conf.m.Unlock()
	backupPath := dataCryptoBackupPath()
	if err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {
		return fmt.Errorf("mkdir notebook crypto backup dir failed: %w", err)
	}
	data, err := json.Marshal(nc)
	if err != nil {
		return fmt.Errorf("marshal notebook crypto backup failed: %w", err)
	}
	if err := atomicWriteFile(backupPath, data); err != nil {
		return fmt.Errorf("write notebook crypto backup failed: %w", err)
	}
	return nil
}

// writeNotebookCryptoBackupData 将指定的 NotebookCrypto 写入备份文件(不依赖 Conf.NotebookCrypto)。
// kek 必须非 nil:在 Checksum 定型后计算 KEKMAC,保证落盘 MAC 与落盘内容一致。
func writeNotebookCryptoBackupData(nc *conf.NotebookCrypto, kek []byte) error {
	if kek == nil {
		return errors.New("cannot generate notebook crypto backup without KEK")
	}
	prepareBackupForWrite(nc)
	nc.KEKMAC = computeKEKMAC(nc, kek)
	if !notebookCryptoConfigurationComplete(nc) {
		return errors.New("cannot write incomplete notebook crypto backup")
	}
	backupPath := dataCryptoBackupPath()
	if err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {
		return fmt.Errorf("mkdir notebook crypto backup dir failed: %w", err)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Free disk space / raise quota on the workspace volume
  2. Check permissions and locks on the existing backup file at dataCryptoBackupPath and remove/repair it if not writable
  3. Verify the backup path is not occupied by a directory and the storage device is healthy (dmesg/SMART)

Example fix

// before: blind re-derivation that fails again
_, err := deriveKEK(password)
// after: precheck writability of the backup location
backupPath := dataCryptoBackupPath()
if err := checkWritableFile(filepath.Dir(backupPath)); err == nil {
    _, err = deriveKEK(password)
}
Defensive patterns

Strategy: try-catch

Validate before calling

f, err := os.OpenFile(dataCryptoBackupPath(), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    // target not writable; fix before calling the API
} else {
    f.Close()
}

Try / catch

if err := saveNotebookCryptoBackup(kek); err != nil {
    if strings.Contains(err.Error(), "write notebook crypto backup failed") {
        // check disk space/permissions on backupPath, then retry save
    }
}

Prevention

When it happens

Trigger: atomicWriteFile(backupPath, data) fails during EnableEncryptedNotebook, deriveKEK, or ChangeMasterPassword — disk full, permission denied on the target file, the path is a directory, or an I/O error on the underlying device.

Common situations: Disk quota/full disk; the backup file exists but is read-only or locked by another process (backup/sync tools, antivirus); the backup path collides with a directory; failing disk or network-mounted workspace.

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