siyuan-note/siyuan · error
enable encrypted notebook failed: failed to persist key…
Error message
enable encrypted notebook failed: failed to persist key backup: %w
What it means
EnableEncryptedNotebook persists the key backup (saveNotebookCryptoBackup) BEFORE committing the new crypto configuration to conf.json. If writing that backup fails, it rolls back the in-memory NotebookCrypto settings to their previous value and returns "enable encrypted notebook failed: failed to persist key backup" wrapping the underlying write error, so the feature is never left half-enabled with keys that only exist in volatile conf.
Solutions
- Check the wrapped underlying error for the actual filesystem cause (permission denied, no space left, etc.) and fix disk space or permissions on the workspace data directory
- Ensure the SiYuan process user owns/can write to the workspace and its data subdirectory (chmod/chown)
- Retry the enable call once the filesystem is writable; the operation is idempotent when no key domain exists yet
- If a stale/partial backup file blocks the write, remove it manually — only safe when no encrypted notebooks exist yet
Example fix
// before
err := model.EnableEncryptedNotebook(password)
// after
if err := model.EnableEncryptedNotebook(password); err != nil {
if strings.Contains(err.Error(), "failed to persist key backup") {
// inspect fs permissions / free space on workspacePath/data before retrying
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check writability of the backup target's directory before enabling
if err := os.MkdirAll(filepath.Dir(model.DataCryptoBackupPath()), 0o755); err != nil { /* abort: cannot write workspace data dir */ }
if err := filelock.WriteFile(model.DataCryptoBackupPath()+".wtest", []byte("ok")); err != nil { /* abort */ } Type guard
func isBackupPersistFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to persist key backup")
} Try / catch
if err := model.EnableEncryptedNotebook(pwd); err != nil {
if isBackupPersistFailure(err) { /* fix fs perms/space reported by wrapped cause, then retry */ }
} Prevention
- Ensure the workspace data directory is writable by the kernel process user
- Monitor free disk space in containers/CI before enabling encryption
- Exclude the workspace from antivirus/backup tools that lock files
- Mount volumes read-write, not read-only
When it happens
Trigger: Calling EnableEncryptedNotebook when saveNotebookCryptoBackup cannot write the backup file: workspace data directory read-only, disk full, filesystem/permission errors, antivirus locking the file, or filelock contention on the backup path.
Common situations: Running SiYuan from a read-only mount or full disk; workspace moved to a directory the kernel user cannot write; permission changes after an OS update; backup path locked by a backup/sync tool; container with a read-only /data volume.
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
- write notebook crypt backup failed
- accessing assets in encrypted notebook
- Conf.Language(388) with escaped relative path…
- create import dir failed
- encrypt notebook metadata failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/49a1565d6960f1a2.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/crypto.go:1077
}
Conf.m.Lock()
previous := *Conf.NotebookCrypto
Conf.NotebookCrypto.Enabled = true
Conf.NotebookCrypto.MasterSalt = salt
Conf.NotebookCrypto.KDFParams = params
Conf.NotebookCrypto.KEKVerifier = verifierCT
Conf.NotebookCrypto.VerifierNonce = verifierNonce
Conf.m.Unlock()
// 先持久化恢复备份,再提交 conf。此时尚无加密笔记本和历史依赖,任一步失败都不会孤立既有密文。
if err := saveNotebookCryptoBackup(kek); err != nil {
// 备份写失败则恢复启用前的内存配置;conf 尚未写入,无需再执行磁盘回滚。
logging.LogErrorf("save notebook crypto backup failed: %s", err)
Conf.m.Lock()
*Conf.NotebookCrypto = previous
Conf.m.Unlock()
return fmt.Errorf("enable encrypted notebook failed: failed to persist key backup: %w", err)
}
// Conf.Save 内部会加 Conf.m,不能在持锁状态下调用(RWMutex 不可重入)。
// 即使配置写入失败,已落盘的备份仍可在下次启动时恢复同一套密钥材料。
Conf.Save()
IncSync()
return nil
}
// DisableEncryptedNotebook 关闭加密笔记本功能。前置:不能有加密笔记本存在,
// 且不能有依赖当前密钥备份的已删除笔记本历史(否则禁用并删除备份会让这些历史永久锁死,违反 §19)。
// 清除全局加密配置(MasterSalt/KEKVerifier),KEK/DEK 不再可用。
func DisableEncryptedNotebook() error {
notebookCryptoMu.Lock()
defer notebookCryptoMu.Unlock()
// 检查是否还有加密笔记本(含 conf 损坏但存在备份的)
ids, listErr := listAllEncryptedBoxIDs()
if listErr != nil {View on GitHub (pinned to 9f775e8a12)