{"record":{"id":"37a6b30b9ede90e0","repo":"siyuan-note/siyuan","slug":"mkdir-notebook-crypt-backup-dir-failed-w","errorCode":null,"errorMessage":"mkdir notebook crypt backup dir failed: %w","messagePattern":"mkdir notebook crypt backup dir failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2529,"sourceCode":"// 全局备份存 MasterSalt/KEKVerifier，per-notebook 备份存 WrappedDEK/WrapNonce。\nconst notebookCryptoBackupFilename = \"notebook-crypto-backup.json\"\n\nfunc notebookCryptoBackupPath(boxID string) string {\n\treturn filepath.Join(util.DataDir, boxID, \".siyuan\", notebookCryptoBackupFilename)\n}\n\n// writeNotebookCryptBackup 写入加密笔记本的 BoxCrypt 备份。\n// 仅在 Encrypted=true 的笔记本上调用，配合 CreateEncryptedBox / ChangeMasterPassword 写入。\nfunc writeNotebookCryptBackup(boxID string, crypt *conf.BoxEncryption) error {\n\tif !ast.IsNodeIDPattern(boxID) {\n\t\treturn errors.New(\"invalid notebook ID\")\n\t}\n\tif err := validateBoxEncryption(crypt); err != nil {\n\t\treturn err\n\t}\n\tbackupPath := notebookCryptoBackupPath(boxID)\n\tif err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir notebook crypt backup dir failed: %w\", err)\n\t}\n\tdata, err := gulu.JSON.MarshalIndentJSON(crypt, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal notebook crypt backup failed: %w\", err)\n\t}\n\tif err := filelock.WriteFile(backupPath, data); err != nil {\n\t\treturn fmt.Errorf(\"write notebook crypt backup failed: %w\", err)\n\t}\n\treturn nil\n}\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)","sourceCodeStart":2511,"sourceCodeEnd":2547,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L2511-L2547","documentation":"writeNotebookCryptBackup creates the directory that will hold the notebook's BoxCrypt backup file (via os.MkdirAll with 0755) and wraps any failure with this message. It is an I/O-level failure creating the backup directory, not a cryptographic problem.","triggerScenarios":"os.MkdirAll(filepath.Dir(backupPath), 0755) fails during CreateEncryptedBox or ChangeMasterPassword — typically because the workspace data directory is read-only, disk is full, the path component exists as a regular file, or permission bits deny creation.","commonSituations":"SiYuan running with a read-only data directory (Docker volume mounted ro, sync client locking files); a stray file occupying the backup directory path; disk quota exhausted; running on Windows with the folder open/locked by another process.","solutions":["Check the error wrapped by %w — fix the underlying cause (permissions, disk space, path conflict)","Ensure the workspace data directory is writable by the SiYuan process user","Remove or rename any regular file that occupies the backup directory path","If running in Docker, mount the workspace volume read-write"],"exampleFix":"// before\nerr := model.ChangeMasterPassword(box, old, new) // fails: mkdir ...: permission denied\n// after\n# fix host permissions first, e.g.:\n# chown -R 1000:1000 /siyuan/workspace\nerr := model.ChangeMasterPassword(box, old, new)","handlingStrategy":"try-catch","validationCode":"// pre-check writability\nprobe := filepath.Join(workspace, \"data\", \".write-test\")\nif err := os.WriteFile(probe, nil, 0644); err != nil {\n    return fmt.Errorf(\"workspace not writable: %w\", err)\n}\nos.Remove(probe)","typeGuard":null,"tryCatchPattern":"if err := model.ChangeMasterPassword(box, old, new); err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) { log.Printf(\"fs failure at %s: %v\", perr.Path, perr.Err) }\n    return err\n}","preventionTips":["Mount workspace volumes read-write and provision correct ownership","Monitor disk free space before encryption operations","Avoid pointing the workspace at network shares or sync-client-locked folders"],"tags":["filesystem","mkdir","permissions","backup"],"backgroundTag":"mkdir-permission-denied","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"}