siyuan-note/siyuan · error
323
323
Error message
Cannot disable encrypted notebooks: deleted-notebook history still depends on the current key backup. Clear that history first
What it means
Thrown by DisableEncryptedNotebook (crypto.go:1086, i18n code 323) when there are no live encrypted notebooks but the history directory still contains deleted encrypted-notebook snapshots. Those snapshots rely on the current MasterSalt/KEKVerifier (stored in the global key backup) to be restorable; disabling the feature would delete the backup and permanently lock the history. The user must clear that encrypted history first.
Source
Thrown at kernel/model/crypto.go:1086
notebookCryptoMu.Lock()
defer notebookCryptoMu.Unlock()
// 检查是否还有加密笔记本(含 conf 损坏但存在备份的)
ids, listErr := listAllEncryptedBoxIDs()
if listErr != nil {
return fmt.Errorf("list encrypted notebooks failed: %w", listErr)
}
if len(ids) > 0 {
return errors.New("cannot disable encrypted notebook feature while encrypted notebooks exist, remove them first")
}
// 检查历史目录中是否存在已删除加密笔记本的历史快照:其恢复仍依赖当前 MasterSalt/KEKVerifier,
// 删除备份前必须先清除这些历史(详见设计 §19)
hasHistory, historyErr := scanEncryptedNotebookHistory()
if historyErr != nil {
return fmt.Errorf("check encrypted notebook history failed: %w", historyErr)
}
if hasHistory {
return errors.New(Conf.Language(323))
}
Conf.m.Lock()
Conf.NotebookCrypto.Enabled = false
Conf.NotebookCrypto.MasterSalt = nil
Conf.NotebookCrypto.KEKVerifier = nil
Conf.NotebookCrypto.VerifierNonce = nil
Conf.m.Unlock()
Conf.Save()
removeNotebookCryptoBackup() // 禁用时清理备份,避免残留旧密钥材料
IncSync()
return nil
}
// restoreNotebookCryptoConfigFromBackup 把备份里的 NotebookCrypto 配置装回本机 conf.json(不需主密码)。
// 用于数据同步/导入 Data.zip 后:备份文件随 DataDir 到达新设备,但本机 conf.json 的 NotebookCrypto 还是空的。
// 此时把 salt/verifier/KDFParams 装回并置 Enabled=true,让 UI 显示"已启用",笔记本显示为锁定(解锁仍需主密码)。View on GitHub (pinned to 251596fc0d)
Solutions
- Clear the encrypted-notebook history entries (delete the relevant snapshot directories under the history folder, or use the history-clear UI) and retry disable.
- If you want to keep the history restorable, do NOT disable; instead keep the feature enabled, or restore the deleted notebook and decrypt it to normal before disabling.
- After history is cleared, confirm scanEncryptedNotebookHistory returns false, then disable.
Defensive patterns
Strategy: validation
Validate before calling
// Before disable, confirm no encrypted-notebook history remains.
hasHist, err := model.HasEncryptedNotebookHistory()
if err != nil {
return err
}
if hasHist {
return errors.New("clear deleted encrypted-notebook history before disabling")
} Try / catch
if err := model.DisableEncryptedNotebook(); err != nil {
if err.Error() == model.Conf.Language(323) {
respond(c, "clear deleted-notebook encrypted history first, then disable")
return
}
respond(c, err.Error())
} Prevention
- Clear deleted-notebook history before disabling the feature.
- If history must stay restorable, keep the feature enabled instead of disabling.
- Educate users that deleted encrypted notebooks live on in history until purged.
When it happens
Trigger: POST /api/notebook/disableEncryptedNotebooks when listAllEncryptedBoxIDs is empty AND scanEncryptedNotebookHistory returns true. A history snapshot directory <HistoryDir>/<ts>-<op>/<boxID>/.siyuan/ contains notebook-crypto-backup.json or a conf.json with Encrypted=true.
Common situations: User deleted an encrypted notebook (its ciphertext moved into history), then tries to disable the feature without purging history. After sync, history snapshots of a deleted encrypted notebook arrived on a new device.
Related errors
- cannot disable encrypted notebook feature while encrypted no
- check encrypted notebook history failed: %w
- attribute view history context is ambiguous [%s]
- list encrypted notebooks failed: %w
- 315
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/551764ec7fa6a6e8.
Report an issue: GitHub.