{"record":{"id":"752b74b56f7c9421","repo":"siyuan-note/siyuan","slug":"read-notebook-crypt-backup-failed-w","errorCode":null,"errorMessage":"read notebook crypt backup failed: %w","messagePattern":"read notebook crypt backup failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2557,"sourceCode":"}\n\n// readNotebookCryptBackup 读取加密笔记本的 BoxCrypt 备份。\n// 备份文件不存在时返回 (nil, nil)，调用方据此区分\"非加密笔记本\"和\"备份不存在\"。\nfunc readNotebookCryptBackup(boxID string) (*conf.BoxEncryption, error) {\n\tif !ast.IsNodeIDPattern(boxID) {\n\t\treturn nil, errors.New(\"invalid notebook ID\")\n\t}\n\tbackupPath := notebookCryptoBackupPath(boxID)\n\tif !filelock.IsExist(backupPath) {\n\t\treturn nil, nil\n\t}\n\treturn readBoxEncryptionFile(backupPath)\n}\n\nfunc readBoxEncryptionFile(backupPath string) (*conf.BoxEncryption, error) {\n\tdata, err := filelock.ReadFile(backupPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read notebook crypt backup failed: %w\", err)\n\t}\n\tvar crypt conf.BoxEncryption\n\tif err = gulu.JSON.UnmarshalJSON(data, &crypt); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal notebook crypt backup failed: %w\", err)\n\t}\n\tif err = validateBoxEncryption(&crypt); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &crypt, nil\n}\n\n// copyAssetDecryptIfEncrypted 把 srcPath 的 asset 复制到 destPath。\n// 若 srcPath 在已解锁的加密笔记本下，读密文→解密→写明文到 destPath（导出目录）；\n// 否则走 filelock.Copy 原路径（字节级复制，密文/明文均可）。\nfunc copyAssetDecryptIfEncrypted(srcPath, destPath string) error {\n\tif err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {\n\t\treturn err\n\t}","sourceCodeStart":2539,"sourceCodeEnd":2575,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L2539-L2575","documentation":"This error wraps a lower-level failure while reading the notebook's BoxCrypt backup file (the JSON envelope that stores the encrypted-notebook key backup). It is produced by readBoxEncryptionFile when filelock.ReadFile fails, preserving the underlying cause via %w. It means the backup file exists (or was expected) but could not be read from disk.","triggerScenarios":"readNotebookCryptBackup finds notebookCryptoBackupPath(boxID) exists, then readBoxEncryptionFile calls filelock.ReadFile(backupPath) and the OS read fails — permission problems, the file vanishing between the IsExist check and the read, disk I/O errors, or a locked file on Windows.","commonSituations":"Running SiYuan as a different user than the one who owns the workspace data; antivirus or backup software holding the file; workspace moved across machines/users with mismatched ownership; failing disk.","solutions":["Check OS permissions/ownership of <workspace>/data/<notebook>/.siyuan/ crypt backup file and fix with chown/chmod or icacls","Close other processes (backup/antivirus/sync tools) locking the file and retry","Check disk health (dmesg/Event Viewer) and free space; restore the file from backup if it is truncated or unreadable","Re-run the kernel as the same user that owns the workspace"],"exampleFix":"// before (OS level)\ncat data/20240101120000-abcd/.siyuan/crypt.json  # permission denied\n// after\nsudo chown -R $USER:$USER data/20240101120000-abcd/.siyuan/\ncat data/20240101120000-abcd/.siyuan/crypt.json  # works","handlingStrategy":"retry","validationCode":"// pre-check readability\nconst fs = require(\"fs\");\nif (!fs.accessSync(backupPath, fs.constants.R_OK)) { /* proceed */ }","typeGuard":null,"tryCatchPattern":"try {\n    await callKernel();\n} catch (e) {\n    if (String(e.message).includes(\"read notebook crypt backup failed\")) {\n        // check file permissions / disk, then retry after fixing\n    }\n}","preventionTips":["Run the kernel as the user who owns the workspace directory","Exclude workspace data/ from antivirus real-time locking where possible","Monitor disk health and free space"],"tags":["filesystem","io","encrypted-notebook"],"backgroundTag":"file-read-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}