{"record":{"id":"551764ec7fa6a6e8","repo":"siyuan-note/siyuan","slug":"323","errorCode":"323","errorMessage":"Cannot disable encrypted notebooks: deleted-notebook history still depends on the current key backup. Clear that history first","messagePattern":"Cannot disable encrypted notebooks: deleted-notebook history still depends on the current key backup\\. Clear that history first","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":1086,"sourceCode":"\tnotebookCryptoMu.Lock()\n\tdefer notebookCryptoMu.Unlock()\n\n\t// 检查是否还有加密笔记本（含 conf 损坏但存在备份的）\n\tids, listErr := listAllEncryptedBoxIDs()\n\tif listErr != nil {\n\t\treturn fmt.Errorf(\"list encrypted notebooks failed: %w\", listErr)\n\t}\n\tif len(ids) > 0 {\n\t\treturn errors.New(\"cannot disable encrypted notebook feature while encrypted notebooks exist, remove them first\")\n\t}\n\t// 检查历史目录中是否存在已删除加密笔记本的历史快照：其恢复仍依赖当前 MasterSalt/KEKVerifier，\n\t// 删除备份前必须先清除这些历史（详见设计 §19）\n\thasHistory, historyErr := scanEncryptedNotebookHistory()\n\tif historyErr != nil {\n\t\treturn fmt.Errorf(\"check encrypted notebook history failed: %w\", historyErr)\n\t}\n\tif hasHistory {\n\t\treturn errors.New(Conf.Language(323))\n\t}\n\n\tConf.m.Lock()\n\tConf.NotebookCrypto.Enabled = false\n\tConf.NotebookCrypto.MasterSalt = nil\n\tConf.NotebookCrypto.KEKVerifier = nil\n\tConf.NotebookCrypto.VerifierNonce = nil\n\tConf.m.Unlock()\n\n\tConf.Save()\n\tremoveNotebookCryptoBackup() // 禁用时清理备份，避免残留旧密钥材料\n\tIncSync()\n\treturn nil\n}\n\n// restoreNotebookCryptoConfigFromBackup 把备份里的 NotebookCrypto 配置装回本机 conf.json（不需主密码）。\n// 用于数据同步/导入 Data.zip 后：备份文件随 DataDir 到达新设备，但本机 conf.json 的 NotebookCrypto 还是空的。\n// 此时把 salt/verifier/KDFParams 装回并置 Enabled=true，让 UI 显示\"已启用\"，笔记本显示为锁定（解锁仍需主密码）。","sourceCodeStart":1068,"sourceCodeEnd":1104,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/crypto.go#L1068-L1104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before disable, confirm no encrypted-notebook history remains.\nhasHist, err := model.HasEncryptedNotebookHistory()\nif err != nil {\n    return err\n}\nif hasHist {\n    return errors.New(\"clear deleted encrypted-notebook history before disabling\")\n}","typeGuard":null,"tryCatchPattern":"if err := model.DisableEncryptedNotebook(); err != nil {\n    if err.Error() == model.Conf.Language(323) {\n        respond(c, \"clear deleted-notebook encrypted history first, then disable\")\n        return\n    }\n    respond(c, err.Error())\n}","preventionTips":["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."],"tags":["encryption","notebook-crypto","history","precondition","lifecycle"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}