siyuan-note/siyuan · error
failed to persist key backup
Error message
failed to persist key backup: %w
What it means
ImportNotebookCryptoBackup wraps any error from writeNotebookCryptoBackupData as "failed to persist key backup: %w". The backup file is written BEFORE the in-memory Conf is committed (so a failure here leaves Conf unchanged and the import can be retried safely); this error means the validated backup could not be durably written to <DataDir>/.siyuan/data-crypto-backup.json.
Solutions
- Check free disk space in the workspace/data partition and free space if needed
- Verify write permissions on <DataDir>/.siyuan/ (and file ownership after archive-based restores)
- Check whether antivirus or backup software locks the target file, then retry
- Retry the import — Conf was not modified, so the operation is safe to repeat
- If it persists, inspect the wrapped cause (%w) from the logs for the exact OS error
Example fix
# before $ ls -l <DataDir>/.siyuan # owned by root, not writable # after $ sudo chown -R $USER <DataDir>/.siyuan $ # retry the import
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight before import:
fi, err := os.Stat(dataDir + "/.siyuan")
if err != nil || !fi.IsDir() { return errors.New("data dir not writable/missing") }
if err := unix.Access(dataDir+"/.siyuan", unix.W_OK); err != nil { return errors.New("no write permission") } Type guard
null
Try / catch
if err := ImportNotebookCryptoBackup(raw, password); err != nil {
var unwrapped error = err
if strings.Contains(err.Error(), "failed to persist key backup") {
// safe to retry: Conf was not modified
log.Printf("persist failed, retry after fixing disk/permissions: %v", unwrapped)
}
} Prevention
- Monitor free disk space on the data volume before recovery operations
- Ensure the data directory is writable by the kernel process user
- Exclude the backup file from antivirus real-time locking where possible
- Because Conf is committed only after the backup succeeds, always retry rather than switching strategies
When it happens
Trigger: ImportNotebookCryptoBackup reaches the persist step after all password/key checks pass, but the underlying mkdir, marshal, or atomicWriteFile of the backup file fails — typically disk full, permission denied on the data directory, or antivirus/file-lock interference on Windows.
Common situations: Full disk during restore on a new device; read-only or permission-restricted data directory (e.g. restored from an archive with wrong ownership); security software holding the target file; failing disk.
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
- Conf.Language(14) (copy resource failed: )
- create AI editor actions directory failed
- create conf dir failed
- create import dir failed:
- create import dir failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/fbc1a06019402733.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/crypto.go:365
if !verifyKEKMAC(nc, kek) {
return errors.New(Conf.Language(317))
}
decrypted, dErr := util.DecryptWithAAD(kek, nc.KEKVerifier, []byte("siyuan:kek-verifier"))
if dErr != nil || string(decrypted) != string(kekVerifierMagic) {
return errors.New(Conf.Language(311)) // 主密码错误
}
// 校验 KEK 能解密现存笔记本和已删除笔记本历史中的 WrappedDEK,避免导入不匹配的备份。
if !verifyKEKAgainstExistingBoxes(kek, nc) || !verifyKEKAgainstEncryptedHistory(kek, nc) {
return errors.New(Conf.Language(316)) // 密钥不匹配
}
nc.KDFParams = params // 确保写回 Conf 的参数已经通过完整校验。
nc.Enabled = true
// 先写 backup,再提交 conf;backup 失败时 conf 尚未改变,可重试
if err := writeNotebookCryptoBackupData(nc, kek); err != nil {
return fmt.Errorf("failed to persist key backup: %w", err)
}
Conf.m.Lock()
*Conf.NotebookCrypto = *nc
Conf.m.Unlock()
Conf.Save()
IncSync()
return nil
}
// saveNotebookCryptoBackup 把当前 NotebookCrypto(含 MasterSalt/KEKVerifier/KDFParams)备份到 DataDir。
// kek 必须非 nil:在 Checksum 定型后计算 KEKMAC 并落盘,保证恢复路径可通过 MAC 校验。
// 无 KEK 生成的备份 KEKMAC 必为空,会被 deriveKEK/恢复路径拒绝,等于制造无法解锁的状态(详见设计 §19)。
func saveNotebookCryptoBackup(kek []byte) error {
if kek == nil {
// 无 KEK 时不得生成当前格式备份:KEKMAC 缺失会被 deriveKEK/恢复路径拒绝,
// 生成即等于制造无法解锁的状态。
return errors.New("cannot generate notebook crypto backup without KEK")
}View on GitHub (pinned to 9f775e8a12)