{"record":{"id":"f5f94acee69a5999","repo":"siyuan-note/siyuan","slug":"write-notebook-crypto-backup-failed-w","errorCode":null,"errorMessage":"write notebook crypto backup failed: %w","messagePattern":"write notebook crypto backup failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":407,"sourceCode":"\t\tConf.m.Unlock()\n\t\treturn errors.New(\"cannot save incomplete notebook crypto configuration\")\n\t}\n\tConf.NotebookCrypto.Spec = nc.Spec\n\tConf.NotebookCrypto.BackupID = nc.BackupID\n\tConf.NotebookCrypto.CreatedAt = nc.CreatedAt\n\tConf.NotebookCrypto.Checksum = nc.Checksum\n\tConf.NotebookCrypto.KEKMAC = nc.KEKMAC // 保持 Conf 与备份文件的 KEKMAC 一致\n\tConf.m.Unlock()\n\tbackupPath := dataCryptoBackupPath()\n\tif err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir notebook crypto backup dir failed: %w\", err)\n\t}\n\tdata, err := json.Marshal(nc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal notebook crypto backup failed: %w\", err)\n\t}\n\tif err := atomicWriteFile(backupPath, data); err != nil {\n\t\treturn fmt.Errorf(\"write notebook crypto backup failed: %w\", err)\n\t}\n\treturn nil\n}\n\n// writeNotebookCryptoBackupData 将指定的 NotebookCrypto 写入备份文件（不依赖 Conf.NotebookCrypto）。\n// kek 必须非 nil：在 Checksum 定型后计算 KEKMAC，保证落盘 MAC 与落盘内容一致。\nfunc writeNotebookCryptoBackupData(nc *conf.NotebookCrypto, kek []byte) error {\n\tif kek == nil {\n\t\treturn errors.New(\"cannot generate notebook crypto backup without KEK\")\n\t}\n\tprepareBackupForWrite(nc)\n\tnc.KEKMAC = computeKEKMAC(nc, kek)\n\tif !notebookCryptoConfigurationComplete(nc) {\n\t\treturn errors.New(\"cannot write incomplete notebook crypto backup\")\n\t}\n\tbackupPath := dataCryptoBackupPath()\n\tif err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir notebook crypto backup dir failed: %w\", err)","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L389-L425","documentation":"saveNotebookCryptoBackup writes the JSON backup with atomicWriteFile after creating the directory; this error wraps a failed atomic write. The backup file (e.g. at the data crypto backup path) could not be written, so the on-disk recovery copy is missing or stale even though Conf in memory was already updated. Encrypted-notebook recovery depends on this file, so it should be resolved immediately.","triggerScenarios":"atomicWriteFile(backupPath, data) fails during EnableEncryptedNotebook, deriveKEK, or ChangeMasterPassword — disk full, permission denied on the target file, the path is a directory, or an I/O error on the underlying device.","commonSituations":"Disk quota/full disk; the backup file exists but is read-only or locked by another process (backup/sync tools, antivirus); the backup path collides with a directory; failing disk or network-mounted workspace.","solutions":["Free disk space / raise quota on the workspace volume","Check permissions and locks on the existing backup file at dataCryptoBackupPath and remove/repair it if not writable","Verify the backup path is not occupied by a directory and the storage device is healthy (dmesg/SMART)"],"exampleFix":"// before: blind re-derivation that fails again\n_, err := deriveKEK(password)\n// after: precheck writability of the backup location\nbackupPath := dataCryptoBackupPath()\nif err := checkWritableFile(filepath.Dir(backupPath)); err == nil {\n    _, err = deriveKEK(password)\n}","handlingStrategy":"try-catch","validationCode":"f, err := os.OpenFile(dataCryptoBackupPath(), os.O_WRONLY|os.O_CREATE, 0644)\nif err != nil {\n    // target not writable; fix before calling the API\n} else {\n    f.Close()\n}\n","typeGuard":null,"tryCatchPattern":"if err := saveNotebookCryptoBackup(kek); err != nil {\n    if strings.Contains(err.Error(), \"write notebook crypto backup failed\") {\n        // check disk space/permissions on backupPath, then retry save\n    }\n}\n","preventionTips":["Ensure adequate free space and quota on the workspace volume","Do not lock or open the backup file exclusively in other tools (sync/backup/AV)","Verify the backup path is a writable file location, not a directory","Re-save the backup after any transient I/O failure so the recovery copy is current"],"tags":["filesystem","file-write","backup","atomic-write","crypto"],"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-14T00:17:10.932Z"}