siyuan-note/siyuan · error
enable encrypted notebook failed: failed to persist key back
Error message
enable encrypted notebook failed: failed to persist key backup: %w
What it means
Thrown by EnableEncryptedNotebook (crypto.go:1055) when saveNotebookCryptoBackup fails while persisting the freshly generated key backup during initial feature enablement. The function rolls back the in-memory NotebookCrypto to its pre-enable snapshot (conf has not been written yet) and returns the wrapped I/O error. This guard exists so that a half-written backup can never leave the system believing encryption is enabled without a recoverable key backup.
Source
Thrown at kernel/model/crypto.go:1055
}
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 251596fc0d)
Solutions
- Free disk space on the data volume and confirm the data directory is writable by the kernel process, then retry enable.
- Check and clear any stale lock on the backup path (dataCryptoBackupPath()) and verify file ownership/permissions.
- If the data directory lives on a network mount, move it to a local writable volume or fix the mount's read/write permissions and retry.
- Inspect the wrapped error chain (the %w tail names the syscall/path) to pinpoint the exact I/O failure.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: confirm the backup path is writable before enable.
func backupPathWritable() error {
p := dataCryptoBackupPath()
f, err := os.CreateTemp(filepath.Dir(p), "crypto-backup-probe-*")
if err != nil {
return fmt.Errorf("backup dir not writable: %w", err)
}
f.Close()
os.Remove(f.Name())
return nil
} Try / catch
if err := model.EnableEncryptedNotebook(password); err != nil {
if strings.Contains(err.Error(), "failed to persist key backup") {
// surface the wrapped I/O cause; advise freeing space / fixing permissions
respond(c, "cannot write key backup: "+err.Error())
return
}
respond(c, err.Error())
} Prevention
- Ensure the data directory is on a writable local volume with adequate free space.
- Run a write-probe on the data directory before enable.
- Exclude the key backup path from exclusive-locking antivirus/sync tools on Windows.
When it happens
Trigger: First-time enable flow: salt generated, KEK derived, verifier encrypted, Conf.NotebookCrypto mutated in memory, then saveNotebookCryptoBackup(kek) returns a non-nil error. The backup write goes to dataCryptoBackupPath(); it fails on disk-full, permission denied, read-only filesystem, path-too-long, or an existing read-only file lock.
Common situations: Data directory on a nearly-full disk, on a network/SMB mount with intermittent write permission, or on read-only media. A leftover lock or a permissions change after a system migration. Antivirus or sync client holding the backup file open exclusively on Windows.
Related errors
- read image failed: %w
- master password migration is pending: %v
- refuse to write decrypted asset inside workspace
- source is not an encrypted asset
- invalid .sy base name [%s]: must end with .sy
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/49a1565d6960f1a2.
Report an issue: GitHub.