{"record":{"id":"3dcdb5f31a6bde53","repo":"siyuan-note/siyuan","slug":"encrypted-notebooks-already-exist-but-the-master-k","errorCode":null,"errorMessage":"Encrypted notebooks already exist but the master key backup is missing. Restore the original conf.json or backup file to re-enable","messagePattern":"Encrypted notebooks already exist but the master key backup is missing\\. Restore the original conf\\.json or backup file to re-enable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":282,"sourceCode":"\ttmpPath := path + \".\" + gulu.Rand.String(7) + \".tmp\"\n\tif err := os.WriteFile(tmpPath, data, 0644); err != nil {\n\t\treturn err\n\t}\n\treturn os.Rename(tmpPath, path)\n}\n\n// ExportNotebookCryptoBackup 把密钥备份文件复制到 export 目录，返回可下载的相对路径。\n// 供用户主动导出保存，作为同步之外的独立恢复途径（详见设计文档 §4.1）。\n// 备份文件本身不含主密码（salt 不保密、verifier 是密文），拿到它也解不开任何数据。\nfunc ExportNotebookCryptoBackup() (downloadPath string, err error) {\n\tnotebookCryptoMu.Lock()\n\tdefer notebookCryptoMu.Unlock()\n\n\tbackupPath := dataCryptoBackupPath()\n\tdata, readErr := filelock.ReadFile(backupPath)\n\tif readErr != nil {\n\t\tif os.IsNotExist(readErr) {\n\t\t\terr = errors.New(Conf.Language(315))\n\t\t\treturn\n\t\t}\n\t\terr = readErr\n\t\treturn\n\t}\n\texportBase := filepath.Join(util.TempDir, \"export\")\n\tif mkErr := os.MkdirAll(exportBase, 0755); mkErr != nil {\n\t\terr = mkErr\n\t\treturn\n\t}\n\t// 用随机名避免不同用户/设备互相覆盖，文件名固定带易识别前缀\n\tfileName := \"notebook-crypto-backup-\" + gulu.Rand.String(7) + \".json\"\n\tdownloadPath = \"/export/\" + url.PathEscape(fileName)\n\tif writeErr := os.WriteFile(filepath.Join(exportBase, fileName), data, 0644); writeErr != nil {\n\t\terr = writeErr\n\t\treturn\n\t}\n\treturn","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/crypto.go#L264-L300","documentation":"ExportNotebookCryptoBackup fails when the on-disk notebook-crypto backup file does not exist (os.IsNotExist). The function copies the persisted backup (data-crypto-backup.json) into the export directory for user download; if there is no backup file to copy, it returns Conf.Language(315). This signals that encrypted notebooks exist or were expected, but the independent recovery backup is missing — a recovery-required state.","triggerScenarios":"User invokes 'export key backup' from the encryption settings UI, but <DataDir>/.siyuan/data-crypto-backup.json is absent. Typical when conf.json still references encryption but the backup was manually deleted, an external sync deleted it, or a prior enable/write failed after partial cleanup.","commonSituations":"User deleted the .siyuan backup file manually; a broken sync removed the backup while leaving encrypted notebook data; conf.json restored from an old copy that points at encryption without a matching backup; filesystem cleanup tools removing hidden files.","solutions":["Restore the original conf.json or a previously exported backup file to <DataDir>/.siyuan/data-crypto-backup.json, then retry export.","If the master password is known and encryption is still enabled in conf.json, regenerate the backup via the re-enable/recovery path rather than exporting a non-existent one.","Locate the backup from another synced device's DataDir and copy it into place."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Confirm the backup file exists before offering export.\nif !filelock.IsExist(filepath.Join(util.DataDir, \".siyuan\", \"data-crypto-backup.json\")) {\n    // do not offer 'export backup'; route user to recovery instead\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Before offering 'export key backup', check the backup file exists.","Keep exported backup copies in a separate safe location so a missing on-disk backup is recoverable.","If the backup is missing while encryption is enabled, treat it as a recovery-required situation and regenerate via the recovery path."],"tags":["crypto","backup","encryption","recovery","filesystem"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}