{"record":{"id":"d03bb29d1e67c9f7","repo":"siyuan-note/siyuan","slug":"encrypted-notebook-is-not-accessible","errorCode":null,"errorMessage":"encrypted notebook is not accessible","messagePattern":"encrypted notebook is not accessible","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/crypto.go","lineNumber":1653,"sourceCode":"}\n\n// mustEncryptionNonce 从刚刚成功生成的密文中提取 nonce。生成密文格式错误属于内部不变量被破坏，直接终止执行。\nfunc mustEncryptionNonce(ciphertext []byte) []byte {\n\tnonce, err := util.EncryptionNonce(ciphertext)\n\tif err != nil {\n\t\tpanic(\"extract encryption nonce failed: \" + err.Error())\n\t}\n\treturn nonce\n}\n\n// GetDEK 取已缓存的 DEK。返回副本，避免外部零化影响缓存。\n// filesys/assets/db 加解密时调用。\nfunc GetDEK(boxID string) ([]byte, error) {\n\tif !ast.IsNodeIDPattern(boxID) {\n\t\treturn nil, errors.New(\"invalid notebook ID\")\n\t}\n\tif IsEncryptedBox(boxID) && !isBoxUnlockedForAccess(boxID) {\n\t\treturn nil, errors.New(\"encrypted notebook is not accessible\")\n\t}\n\tcachedDEKsLock.RLock()\n\tdefer cachedDEKsLock.RUnlock()\n\tdek, ok := cachedDEKs[boxID]\n\tif !ok {\n\t\treturn nil, errors.New(\"no DEK cached for box \" + boxID)\n\t}\n\tret := make([]byte, len(dek))\n\tcopy(ret, dek)\n\treturn ret, nil\n}\n\n// ClearDEK 清除指定笔记本的 DEK。Unmount 单个加密笔记本时调用。\nfunc ClearDEK(boxID string) {\n\tLockBox(boxID)\n}\n\n// ChangeMasterPassword 改主密码：用旧密码校验后，用新密码派生新 KEK，","sourceCodeStart":1635,"sourceCodeEnd":1671,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/crypto.go#L1635-L1671","documentation":"Thrown by GetDEK when IsEncryptedBox(boxID) returns true but isBoxUnlockedForAccess(boxID) returns false. This means the notebook is recognized as encrypted, but the user has not yet entered the master password to unlock it (or it has been auto-locked). The DEK is not in the cachedDEKs map, so file/asset/db operations that need it cannot proceed.","triggerScenarios":"Called from filesys, asset serving (api/asset.go:346,416), file operations (api/file.go:64), export (api/export.go:1170), and upload (model/upload.go:604). Fires when these internal paths try to read/write encrypted data for a notebook that is currently locked. For example: serving a thumbnail for a locked encrypted notebook, or a background sync/index touching encrypted .sy files.","commonSituations":"Auto-lock timer expired (AutoLockMinutes) and the notebook was locked while a background operation was in-flight. User locked the notebook manually but a plugin or sync job still tries to access its data. SiYuan restarted (DEKs don't persist across restarts) and background initialization tries to index encrypted notebooks before the user unlocks them.","solutions":["Unlock the notebook first by calling UnlockBox with the master password.","If this fires during background operations after restart, ensure the user is prompted to unlock encrypted notebooks before those operations run.","Check the auto-lock timeout setting (AutoLockMinutes) — if it's too short for the user's workflow, increase it.","For API consumers, call getEncryptedNotebookStatus to check unlock state before attempting operations that require DEK access."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Check unlock status before accessing encrypted data:\nif model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {\n    // prompt user to unlock, or skip the operation\n    return\n}\ndek, err := model.GetDEK(boxID)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check IsBoxUnlocked before file/asset operations on encrypted notebooks.","Use getEncryptedNotebookStatus API to verify unlock state in the UI.","Configure a reasonable AutoLockMinutes to balance security and convenience."],"tags":["encryption","notebook-locked","access-control","go"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}