{"record":{"id":"cac525d38a94164d","repo":"siyuan-note/siyuan","slug":"save-encrypted-notebook-conf-failed-w","errorCode":null,"errorMessage":"save encrypted notebook conf failed: %w","messagePattern":"save encrypted notebook conf failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2658,"sourceCode":"\t\t\tcleanupFailedEncryptedBox(createdBoxID)\n\t\t\tid = \"\"\n\t\t}\n\t}()\n\n\tenc, dek, err := WrapNewDEK(id, kek)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tbox := &Box{ID: id}\n\tboxConf := box.GetConf()\n\tboxConf.Encrypted = true\n\tboxConf.BoxCrypt = enc\n\tif err = encryptBoxMetadata(id, boxConf, dek); err != nil {\n\t\treturn \"\", fmt.Errorf(\"encrypt notebook metadata failed: %w\", err)\n\t}\n\tif err = box.SaveConf(boxConf); err != nil {\n\t\treturn \"\", fmt.Errorf(\"save encrypted notebook conf failed: %w\", err)\n\t}\n\tif err = writeNotebookCryptBackup(id, enc); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write notebook crypt backup failed: %w\", err)\n\t}\n\t// 回读校验加密配置已落盘，避免写失败后按普通笔记本处理\n\tverifyConf := box.GetConf()\n\tif verifyConf == nil || !verifyConf.Encrypted || verifyConf.BoxCrypt == nil {\n\t\terr = errors.New(\"encrypted notebook metadata verification failed after write\")\n\t\treturn \"\", err\n\t}\n\tmarkRuntimeEncryptedBox(id)\n\tinvalidateEncryptedPublishAccessCache()\n\n\t// 复用刚派生的 DEK 直接开 db + 缓存，省去再次 Argon2id 解锁\n\tcachedDEKsLock.Lock()\n\tif err = sql.OpenEncryptedDB(id, dek); err != nil {\n\t\tcachedDEKsLock.Unlock()\n\t\treturn \"\", err","sourceCodeStart":2640,"sourceCodeEnd":2676,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L2640-L2676","documentation":"After the metadata is encrypted, box.SaveConf(boxConf) persists the updated box configuration (Encrypted=true, BoxCrypt envelope). If saving fails, this wrapped error aborts the conversion. A notebook whose conf was not saved would still claim to be plain on next load, so the operation must not continue.","triggerScenarios":"box.SaveConf fails writing data/<box>/conf.json — permission denied, disk full, path issues, or serialization problems while persisting the box configuration struct.","commonSituations":"data/ directory owned by root after running the kernel with sudo once; OneDrive/Dropbox/backup tool locking conf.json on Windows; disk quota exceeded on the workspace volume.","solutions":["Check kernel logs for the wrapped cause and fix the underlying write error (permissions, disk space)","Ensure no other process locks data/<box>/conf.json and retry enable-encryption","Verify conf.json is writable: touch data/<box>/conf.json as the user running the kernel"],"exampleFix":"// before\nencrypt -> save encrypted notebook conf failed: ... disk full\n// after\ndf -h <workspace>          # free space\nclean up, then retry the operation","handlingStrategy":"try-catch","validationCode":"const fs = require(\"fs\");\nconst confPath = path.join(workspace, \"data\", boxID, \"conf.json\");\nfs.accessSync(confPath, fs.constants.W_OK);","typeGuard":null,"tryCatchPattern":"try {\n    await enableNotebookEncryption(boxID, password);\n} catch (e) {\n    if (String(e.message).includes(\"save encrypted notebook conf failed\")) {\n        checkDiskSpaceAndLocks(confPath);\n        // retry after fixing; operation aborted safely\n    }\n}","preventionTips":["Avoid running other processes (editors, sync daemons) that write conf.json concurrently","Verify ownership/permissions after moving a workspace between machines or users","Monitor disk quota on the workspace volume"],"tags":["filesystem","configuration","notebook"],"backgroundTag":"file-write-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}